2012-01-27 13 views
14

Tengo una lista anidada,OrdenarPor/ThenBy looping - Listas anidadas en C#

List<List<String>> intable; 

donde quisiera ordenar todas las columnas. El problema es que la cantidad de columnas depende de la entrada del usuario.

Clasificación de la lista como esta funciona bien (suponiendo 4 columnas para este ejemplo)

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(); 

Pero, cuando lo puse en un bucle, como esto:

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

de TI ya no funciona correctamente, y ordena solo la cuarta columna.

+1

Ver este [http://social.msdn.microsoft .com/forums/en-US/linqprojectgeneral/thread/61e502b4-6795-4e51-b70e-2be642cfc413 /] (http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/61e502b4-6795 -4e51-b70e-2be642cfc413 /) –

Respuesta

24

Este es un caso de acceso a un cierre modificado. Cambiar el código para esto y va a trabajar:

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 escrito un two-part article que describe el problema. La razón por la que no funciona como espera es, en resumen, porque LINQ solo está utilizando el último valor de i cuando se evalúa al llamar al ToList(). Es lo mismo que si hubiera escrito:

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 confirmó que el comportamiento de cierre cambiará en C# 5. [SO Link Here] (http://stackoverflow.com/a/8899347/498969) –

+6

@ AdamSpicer: No cambiará para los bucles "for", solo para los bucles "foreach". –

+0

@EricLippert, ¡Gracias por la aclaración! –

0

Crear un comparador

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); 
    } 
} 

continuación, ordenar la lista como esta

intable.Sort(new StringListComparer()); 
Cuestiones relacionadas