2010-11-05 25 views
13

Digamos que estoy usando el método LINQ array .Distinct(). El resultado no está ordenado.¿Cómo se clasifica el método LINQ .distinct?

Bueno, todo está "ordenado" si conoce la lógica utilizada para producir el resultado.

Mi pregunta es sobre el conjunto de resultados. ¿La matriz resultante estará en el orden "primero distinto" o quizás en el orden "último distinto"?

¿Puedo nunca contar con alguna orden?

Este es el viejo problema de "eliminar cadenas duplicadas", pero estoy investigando la solución LINQ.

Respuesta

20

Suponiendo que se refiere a LINQ to Objects, básicamente mantiene un conjunto de todos los resultados que ha devuelto hasta el momento, y solo cede el elemento "actual" si no se ha producido antes. Entonces, los resultados están en el orden original, con duplicados eliminados. Algo como esto (excepto con la comprobación de errores, etc):

public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source) 
{ 
    HashSet<T> set = new HashSet<T>(); 

    foreach (T item in source) 
    { 
     if (set.Add(item)) 
     { 
      // New item, so yield it 
      yield return item; 
     } 
    } 
} 

Esto no está garantizado - pero no puedo imaginar una aplicación más sensata. Esto permite que Distinct() sea tan vago como sea posible: los datos se devuelven tan pronto como sea posible y solo se almacena en el búfer la cantidad mínima de datos.

Confiar en esto sería una mala idea, pero puede resultar instructivo saber cómo funciona la implementación actual (al parecer). En particular, puede observar fácilmente que comienza devolviendo datos antes de agotar la secuencia original, simplemente creando una fuente que inicia sesión cuando produce datos para ser consumidos por Distinct, y también inicia sesión cuando recibe datos de Distinct.

+3

También puede agregar su propio método de extensión (por ejemplo, DistinctOrdered ) con la implementación que Jon proporcionó. De esta forma, siempre tendrá una implementación con un orden definido independientemente de la versión de .NET Framework. – Karsten

+0

añadiendo a [Datos de Jon Skeet] (http://meta.stackexchange.com/questions/9134/jon-skeet-facts) - El [.NET Reference Source] (https://referencesource.microsoft.com/# System.Core/System/Linq/Enumerable.cs, 4ab583c7d8e84d6d) se basa en las respuestas de Jon Skeet – Slai

1

El método Distinct no garantiza oficialmente un pedido hasta donde yo sé, aunque en la práctica la implementación de LINQ to Objects devuelve los grupos en el orden en que aparecen por primera vez en la fuente enumerable.

Si utiliza LINQ to SQL, por ejemplo, corresponde a la base de datos decidir en qué orden desea devolver los resultados y, a continuación, no debe confiar en que esta orden sea uniforme de una llamada a la siguiente.

3

Nunca puede contar con ningún pedido. Sería completamente permisible para LINQ implementar esto usando tablas hash (y de hecho, creo que ES implementado de esa manera en .NET 4).

1

Supongo que está utilizando una tabla hash para producir el conjunto de claves distintas, y producir la salida en orden por los valores hash.

8

El docs dicen:

"La secuencia resultado es desordenada."

+0

Lo sé. Mi punto es que la noción de que el orden es "aleatorio" realmente no se sostiene ... a menos que el método sea completamente extraño para mí. – Matthew

+4

@matthew: Ok, pero usted pregunta "¿Puedo contar con alguna orden?"Dado que los documentos indican claramente que el resultado no está ordenado, no puede contar con ningún pedido. Si está en cierto orden hoy, con la siguiente corrección de errores .NET que puede cambiar, ya que no hay orden de garantía. –

+1

@matthew: Verifique la respuesta de Jon. En el mejor de los casos, el orden es el mismo en el que ingresaron los datos, pero como todo el mundo ha estado diciendo, y según los documentos, no hay garantía de ningún pedido en particular. Si necesita un pedido, agregue un pedido por el Linq, por ej., 'Var result = sourceItems.Distinct(). OrderBy (item => item.ValueToOrderOn)' – Will

Cuestiones relacionadas