2012-01-27 8 views
14

ho una lista annidata,OrderBy/ThenBy looping - Liste annidate in C#

List<List<String>> intable; 

dove vorrei ordinare tutte le colonne. Il problema è che il numero di colonne dipende dall'input dell'utente.

Ordinamento della lista come questo funziona bene (assumendo 4 colonne per questo esempio)

var tmp = intable.OrderBy(x => x[0]); 
tmp = tmp.ThenBy(x => x[1]); 
tmp = tmp.ThenBy(x => x[2]); 
tmp = tmp.ThenBy(x => x[3]); 
intable = tmp.ToList(); 

Ma, quando ho messo in un ciclo, come questo:

var tmp = intable.OrderBy(x => x[0]); 
for (int i = 1; i <= 3; i++) 
{ 
     tmp = tmp.ThenBy(x => x[i]); 
} 
intable = tmp.ToList(); 

esso non funziona più correttamente e ordina solo la quarta colonna.

+1

Vedere questo [http://social.msdn.microsoft .com/forum/it-IT/linqprojectgeneral/thread/61e502b4-6795-4e51-b70e-2be642cfc413 /] (http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/61e502b4-6795 -4e51-b70e-2be642cfc413 /) –

risposta

24

Questo è un caso di accesso a una chiusura modificata. Modificare il codice per questo e funzionerà:

var tmp = intable.OrderBy(x => x[0]); 
for (int i = 1; i <= 3; i++) { 
    var thisI = i; 
    tmp = tmp.ThenBy(x => x[thisI]); 
} 
intable = tmp.ToList(); 

Eric Lippert ha scritto un two-part article che descrive il problema. Il motivo per cui non funziona come previsto è, in breve, perché LINQ utilizza solo l'ultimo valore di i quando viene valutato quando si chiama ToList(). E 'lo stesso come se si fosse scritto:

var tmp = intable.OrderBy(x => x[0]); 
tmp = tmp.ThenBy(x => x[3]); 
tmp = tmp.ThenBy(x => x[3]); 
tmp = tmp.ThenBy(x => x[3]); 
intable = tmp.ToList(); 
+5

Eric Lippert ha confermato che il comportamento di chiusura cambierà in C# 5. [SO Link Here] (http://stackoverflow.com/a/8899347/498969) –

+6

@AdamSpicer: Non cambierà per cicli "for", solo per cicli "foreach". –

+0

@EricLippert, grazie per il chiarimento! –

0

Creare un operatore di confronto

class StringListComparer : IComparer<List<string>> 
{ 
    public int Compare(List<string> x, List<string> y) 
    { 
     int minLength = Math.Min(x.Count, y.Count); 
     for (int i = 0; i < minLength; i++) { 
      int comp = x[i].CompareTo(y[i]); 
      if (comp != 0) { 
       return comp; 
      } 
     } 
     return x.Count.CompareTo(y.Count); 
    } 
} 

quindi ordinare l'elenco come questo

intable.Sort(new StringListComparer());