Conservando el orden con LINQ

Uso las instrucciones de LINQ to Objects en una matriz ordenada. ¿Qué operaciones no debo hacer para asegurarme de que el orden de la matriz no se modifique?

Examiné los métodos de System.Linq.Enumerable , descartando cualquiera que devolviera resultados que no sean de IEnumerable. Revisé los comentarios de cada uno para determinar cómo el orden del resultado diferiría del orden de la fuente.

Conserva el orden por completo Puede asignar un elemento de origen por índice a un elemento de resultado

  • AsEnumerable
  • Emitir
  • Concat
  • Seleccionar
  • ToArray
  • Listar

Conserva el orden Los elementos se filtran, pero no se vuelven a ordenar.

  • Distinto
  • Excepto
  • Intersecarse
  • OfType
  • Omitir
  • SkipWhile
  • Tomar
  • TakeWhile
  • Dónde
  • Zip (nuevo en .net 4)

Destruye el pedido: no sabemos en qué orden esperar resultados.

  • ToDictionary
  • Para buscar

Redefine el pedido explícitamente: utilícelos para cambiar el orden del resultado

  • OrderBy
  • OrderByDescending
  • Marcha atrás
  • Entonces por
  • ThenByDescending

Redefine el orden según algunas reglas.

  • GroupBy: los objetos IGrouping se generan en un orden basado en el orden de los elementos en el origen que produjo la primera clave de cada IGrouping. Los elementos en una agrupación se producen en el orden en que aparecen en la fuente.
  • GroupJoin – GroupJoin conserva el orden de los elementos de outer, y para cada elemento de outer, el orden de los elementos de coincidencia desde inner.
  • Unir – conserva el orden de los elementos de exterior, y para cada uno de estos elementos, el orden de los elementos correspondientes del interior.
  • SelectMany: para cada elemento de origen, se invoca el selector y se devuelve una secuencia de valores.
  • Unión: cuando se enumera el objeto devuelto por este método, Union enumera primero y segundo en ese orden y arroja cada elemento que aún no se ha cedido.

Editar: me he movido de Distintivo a conservar orden basado en esta implementación .

private static IEnumerable DistinctIterator (IEnumerable source, IEqualityComparer comparer) { Set set = new Set(comparer); foreach (TSource element in source) if (set.Add(element)) yield return element; } 

¿Estás hablando de SQL o de arreglos? Para decirlo de otra manera, ¿estás usando LINQ to SQL o LINQ to Objects?

Los operadores de LINQ to Objects no cambian su fuente de datos original, sino que crean secuencias que están efectivamente respaldadas por la fuente de datos. Las únicas operaciones que cambian el orden son OrderBy / OrderByDescending / ThenBy / ThenByDescending, e incluso entonces, estas son estables para elementos igualmente ordenados. Por supuesto, muchas operaciones filtran algunos elementos, pero los elementos que se devuelven estarán en el mismo orden.

Si se convierte a una estructura de datos diferente, por ejemplo, con ToLookup o ToDictionary, no creo que el orden se conserve en ese punto, pero eso es algo diferente de todos modos. (El orden de los valores de mapeo a la misma clave se conserva para las búsquedas, creo).

Si está trabajando en una matriz, parece que está utilizando LINQ-to-Objects, no SQL; ¿puedes confirmar? La mayoría de las operaciones LINQ no reordenan nada (la salida estará en el mismo orden que la entrada), así que no aplique otro tipo (OrderBy [Descending] / ThenBy [Descending]).

[Editar: como Jon puso más claro; LINQ generalmente crea una nueva secuencia, dejando solo los datos originales]

Tenga en cuenta que al presionar los datos en un Dictionary<,> (ToDictionary) se mezclarán los datos, ya que el diccionario no respeta ningún orden de clasificación en particular.

Pero las cosas más comunes (Seleccionar, Dónde, Omitir, Tomar) deberían estar bien.

Encontré una gran respuesta en una pregunta similar que hace referencia a la documentación oficial. Para citarlo:

Para los métodos Enumerable (LINQ to Objects, que se aplica a List ), puede confiar en el orden de los elementos devueltos por Select , Where o GroupBy . Este no es el caso para cosas que son inherentemente desordenadas como ToDictionary o Distinct .

De la documentación de Enumerable.GroupBy :

Los IGrouping en un orden basado en el orden de los elementos en el origen que produjo la primera clave de cada IGrouping . Los elementos en una agrupación se producen en el orden en que aparecen en la source .

Esto no es necesariamente cierto para los métodos de extensión IQueryable (otros proveedores de LINQ).

Fuente: ¿Los métodos enumerables de LINQ mantienen el orden relativo de los elementos?

Cualquier ‘grupo por’ o ‘orden por’ posiblemente cambiará el orden.