2010-10-15 17 views
68

Ho 2 elenchi di oggetti, uno è solo un elenco di ints, l'altro è un elenco di oggetti ma gli oggetti hanno una proprietà ID.Ordinare una lista con un'altra

Quello che voglio fare è ordinare l'elenco degli oggetti tramite il suo ID nello stesso ordine della lista di interi.

Ive suonato in giro per un po 'di tempo cercando di farlo funzionare, finora nessuna gioia,

Ecco quello che ho finora ...

//************************** 
//*** Randomize the list *** 
//************************** 
if (Session["SearchResultsOrder"] != null) 
{ 
    // save the session as a int list 
    List<int> IDList = new List<int>((List<int>)Session["SearchResultsOrder"]); 
    // the saved list session exists, make sure the list is orded by this 
    foreach(var i in IDList) 
    { 
     SearchData.ReturnedSearchedMembers.OrderBy(x => x.ID == i); 
    } 
} 
else 
{ 
    // before any sorts randomize the results - this mixes it up a bit as before it would order the results by member registration date       
    List<Member> RandomList = new List<Member>(SearchData.ReturnedSearchedMembers); 
    SearchData.ReturnedSearchedMembers = GloballyAvailableMethods.RandomizeGenericList<Member>(RandomList, RandomList.Count).ToList(); 

    // save the order of these results so they can be restored back during postback 
    List<int> SearchResultsOrder = new List<int>(); 
    SearchData.ReturnedSearchedMembers.ForEach(x => SearchResultsOrder.Add(x.ID)); 
    Session["SearchResultsOrder"] = SearchResultsOrder; 
} 

Il punto di questo è quindi, quando un utente cerca i membri, inizialmente vengono visualizzati in ordine casuale, quindi se fanno clic sulla pagina 2, rimangono in tale ordine e vengono visualizzati i 20 risultati successivi.

Ho letto dell'ICompare che posso utilizzare come parametro nella clausola Linq.OrderBy, ma non riesco a trovare esempi semplici.

Spero in una soluzione di stile LINQ elegante e molto semplice, posso sempre sperare.

Qualsiasi aiuto è più apprezzato.

+4

Hai preso in considerazione l'idea di eseguire un collegamento linq tra i due elenchi eseguendo un ordinamento? – RQDQ

+0

Suggerimento: è necessario salvare l'ordine originale come dizionario: id 2 indice. –

+3

Possibile duplicato di http://stackoverflow.com/questions/3470098/linq-list-sort-based-on-another-list – goodeye

risposta

116

Un'altra LINQ-approccio:

var orderedByIDList = from i in ids 
         join o in objectsWithIDs 
         on i equals o.ID 
         select o; 
+0

Quanto è performante? –

+7

La mia esperienza personale è che Linq è in generale molto più performante di quanto molti pensino, nella maggior parte dei casi è solo zucchero sintattico che esegue le stesse operazioni dell'altro codice, quindi di solito non si sente la differenza. In realtà, per questo caso speciale so solo che funziona, suppongo che se non sta andando bene, allora dovrai scegliere una struttura dati completamente diversa, perché questo join completo di liste richiederà sempre un po 'di tempo, indipendentemente da come lo fai . –

24

Un modo per farlo:

List<int> order = ....; 
List<Item> items = ....; 

Dictionary<int,Item> d = items.ToDictionary(x => x.ID); 

List<Item> ordered = order.Select(i => d[i]).ToList(); 
+1

Si presume che per ogni int nella lista ordini, un elemento corrispondente esista negli articoli lista ... –

+1

'order.Where (d.ContainsKey) .Seleziona (...)' o Select/SelectMany con una funzione più lunga che utilizza TryGetValue risolve tale problema. – Jimmy

9

Join è il miglior candidato, se si desidera far corrispondere il numero intero esatto (se nessuna corrispondenza si è trovato ottenere una sequenza vuota). Se si desidera ottenere semplicemente l'ordinamento dell'altro elenco (e se il numero di elementi in entrambi gli elenchi è uguale), è possibile utilizzare Zip.

var result = objects.Zip(ints, (o, i) => new { o, i}) 
        .OrderBy(x => x.i) 
        .Select(x => x.o); 

Piuttosto leggibile.

+0

Nota importante: ciò richiede che l'elenco 'ints' sia ordinato in primo luogo. La risposta accettata no. – Thorarin

+0

@Thorarin no, penso. Perché dici così? Ordiniamo 'ints' comunque per ottenere l'ordinamento, quindi non è necessario che gli interi siano ordinati in primo luogo. – nawfal

+0

@Thorarin, qualcos'altro è sbagliato allora. Sono sicuro del mio codice :) – nawfal

4

Ecco un metodo di estensione che incapsula Simon D.'s response per gli elenchi di qualsiasi tipo.

public static IEnumerable<TResult> SortBy<TResult, TKey>(this IEnumerable<TResult> sortItems, 
                 IEnumerable<TKey> sortKeys, 
                 Func<TResult, TKey> matchFunc) 
{ 
    return sortKeys.Join(sortItems, 
         k => k, 
         matchFunc, 
         (k, i) => i); 
} 

Usage è qualcosa di simile:

var sorted = toSort.SortBy(sortKeys, i => i.Key); 
13

Non una risposta a questa esatto domanda, ma se si hanno due array, v'è un sovraccarico di Array.Sort che prende l'array per ordinare e una matrice da utilizzare come 'chiave'

https://msdn.microsoft.com/en-us/library/85y6y2d3.aspx

Array.Sort Method (Array, Array)
Ordina una coppia di oggetti Array unidimensionali (uno contiene i tasti e l'altra contiene gli elementi corrispondenti) in base alle chiavi in ​​ primo Array utilizzando il Implementazione IComparable di ogni chiave.

+0

Qualche idea su come rendere questo lavoro per gli elenchi? Sono qui ** perché ** Devo lavorare con le liste e non posso usare questa bella cosa di ordinamento di array. – Bitterblue

0

Una possibile soluzione:

myList = myList.OrderBy(x => Ids.IndexOf(x.Id)).ToList(); 

Nota: utilizzare questo se si lavora con In-Memory liste, non funziona per IQueryable tipo, come IQueryable non contiene una definizione per IndexOf

Problemi correlati