2011-09-06 18 views
5

Ho un elenco di Func definire un ordinamento:LINQ to Objects ordinazione con il numero arbitrario di parametri

var ordering = new List<Func<Person, IComparable>> 
       { x => x.Surname, x => x.FirstName }; 

posso ordinare i risultati con qualcosa di simile ...

people = people.OrderBy(ordering[0]).ThenBy(ordering[1]); 

Sono cercando di capire come fare quanto sopra quando l'elenco può contenere un numero qualsiasi di ordini sequenziali. È possibile?

risposta

6
people = people.OrderBy(ordering[0]).ThenBy(ordering[1]).ThenBy(ordering[2]); 

è lo stesso di

var orderedPeople = people.OrderBy(ordering[0]); 
orderedPeople = orderedPeople.ThenBy(ordering[1]); 
orderedPeople = orderedPeople.ThenBy(ordering[2]); 
people = orderedPeople; 

quindi è sufficiente scrivere un ciclo come questo:

if (ordering.Count != 0) 
{ 
    var orderedPeople = people.OrderBy(ordering[0]); 
    for (int i = 1; i < ordering.Count; i++) 
    { 
     orderedPeople = orderedPeople.ThenBy(ordering[i]); 
    } 
    people = orderedPeople; 
} 
+0

che in realtà non hanno bisogno di verificare la presenza di un conteggio, se si passa ciò che viene fatto nel ciclo – msarchet

+0

Non mi sono reso conto che il bit "è uguale a" era vero per qualche motivo. Pensavo che dovessero seguire direttamente. Molte grazie. – fearofawhackplanet

+0

hmmmm ... in realtà non sono la stessa cosa. 'ThenBy' opera su un' OrderedEnumerable ', che è il modo in cui l'ho ricordato. Penso di poter ovviare a questo però. – fearofawhackplanet

3

Si dovrebbe essere in grado di fare qualcosa di simile a questo

people = people.OrderBy(ordering[0]) 
foreach(var order in ordering.Skip(1)) 
{ 
    people = people.ThenBy(order); 
} 

Al ternately

for(i = 0; i < ordering.Count; i++) 
{ 
    people = i == 0 ? people.OrderBy(ordering[i]) : people.ThenBy(ordering[i]); 
} 
2

Ricordare che l'esecuzione di LINQ è differita. È possibile costruire l'espressione in sequenza prima di accedere ai risultati, facendo qualcosa di simile:

var ordered = unordered.OrderBy(ordering.First()); 
foreach (var orderingItem in ordering.Skip(1)) 
{ 
    ordered = ordered.ThenBy(orderingItem); 
} 
4

Come altri hanno già detto, è possibile utilizzare un ciclo per fare questo.

Se si preferisce, è possibile anche utilizzare il Aggregate dell'operatore:

// Requires a non-empty ordering sequence. 
var result2 = ordering.Skip(1) 
         .Aggregate(people.OrderBy(ordering.First()), Enumerable.ThenBy); 

(o)

// Shorter and more "symmetric" but potentially more inefficient. 
// x => true should work because OrderBy is a stable sort. 
var result = ordering.Aggregate(people.OrderBy(x => true), Enumerable.ThenBy); 
+1

Mi piace la concisione di questi, grazie – fearofawhackplanet