2011-06-13 7 views
5

Actualmente, estoy ordenar una lista usando LINQ a objetos, a continuación, haciendo un ToList() en los resultados:Convertir LINQ OrdenarPor a inplace lista de ordenación

var SortedPossibleMoveLocations = (from PML in PossibleMoveLocations 
            orderby Randomiser.Next() 
            orderby IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0 
            orderby PossibleMoveLocationOrdering(PML) 
            select PML).ToList(); 

Quiero convertir esto para hacer un tipo in-situ, i adivina usando el método List<T>.Sort(). Si solo estuviera ordenando por una cosa, sabría cómo hacer esto, sin embargo, como estoy ordenando por PossibleMoveLocationOrdering (que devuelve int) luego por IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0 que evalúa a int, entonces por Randomiser.Next() (que devuelve una combinación aleatoria) no se como hacer esto.

Pregunta: ¿Cómo escribo la función de comparación (o hay un método mejor) para hacer un tipo implace de la consulta LINQ anterior?

+2

Tenga en cuenta que OrdenarPor múltiple es casi siempre mal * * - que no va a añadir el 'ThenBy', por lo que en realidad va a invertir la prioridad de ordenación. Debe ser una sola OrdenarPor con múltiples expresiones –

+0

entiendo voy a conseguir ordenar lo contrario de OrdenarPor x, y, z. (Aunque escribí esto antes de saber sobre la sintaxis de orden única). Es por eso que en el texto debajo del código, aclaro qué tiene presidencia. Gracias por la informacion sin embargo. –

Respuesta

10

Para empezar, especificando tres cláusulas orderby es una mala idea - en su lugar, especifique múltiples ordenamientos sólo mediante el uso de separación por comas.

Tampoco estoy interesado en la idea de utilizar Randomiser.Next() para el pedido, pero eso es un aparte.

Su consulta LINQ debería tener este aspecto (aún con Randomiser en el momento):

var query = (from PML in PossibleMoveLocations 
      orderby PossibleMoveLocationOrdering(PML), 
        IsSameType(PML) ? (_Owner[PML] as TileFlowing).UnitsWithin : 0, 
        Randomiser.Next() 
      select PML).ToList(); 

Personalmente me gustaría sólo tiene que utilizar la notación de puntos para esto:

var query = PossibleMoveLocations 
       .OrderBy(pml => PossibleMoveLocationOrdering(PML)) 
       .ThenBy(pml => IsSameType(pml) ? 
            (_Owner[pml] as TileFlowing).UnitsWithin : 0) 
       .ThenBy(pml => Randomiser.Next()) 
       .ToList(); 

Para ordenar en su lugar, que básicamente necesita un Comparison<T> o IComparer<T> que puede probar varias cosas, y también una aplicación que crea un comparador utilizando propiedades. Puede hacerlo manualmente (según el código de Marc), pero como suele suceder, tengo algunas clases de ayuda y los métodos de extensión en MiscUtil:

var comparer = ProjectionComparer<PossibleMove> 
        .Create(pml => PossibleMoveLocationOrdering(PML)); 
        .ThenBy(pml => IsSameType(pml) ? ...) 
        .ThenBy(...); 

list.Sort(comparer); 

Tenga en cuenta que el uso de un Randomizer aquí es definitivamente una mala idea, ya se llamará en cada comparación (para objetos con las primeras partes iguales) ... esto puede conducir a una comparación inconsistente tal que x < y < z < x.

+0

¿Cómo sería una alternativa a ser orderBy por un número aleatorio en la final (todo otra orden por los valores son iguales) caso? –

+0

Además, ¿el uso de múltiples pedidos es una mala idea puramente debido a la legibilidad, o existe alguna otra razón? –

+0

@George: Básicamente no tienes un pedido consistente en ese caso. Si no puede distinguir entre dos objetos consistentemente, ¿por qué no simplemente devuelve 0 al compararlos? –

6

Lo más común es:

list.Sort((x,y) => { 
    int result = /* first comparison, for example 
        string.Compare(x.Name, y.Name) */ 
    if (result == 0) result = /* second comparison, 
           for example x.Id.CompareTo(y.Id) */ 
    ... 
    if (result == 0) result = /* final comparison */ 
    return result; 
}); 

o similar (tal vez en una clase comparador, si no es trivial).

Cuestiones relacionadas