2009-11-04 22 views
59

Necesito determinar si dos conjuntos contienen exactamente los mismos elementos. El orden no importa.LINQ: Determine si dos secuencias contienen exactamente los mismos elementos

Por ejemplo, estas dos matrices deben considerarse iguales:

IEnumerable<int> data = new []{ 3,5,6,9 }; 
IEnumerable<int> otherData = new []{ 6,5,9,3} 

Un conjunto no puede contener elementos, que no están en el otro.

¿Se puede hacer esto utilizando los operadores de consulta incorporados? ¿Y cuál sería la forma más eficiente de implementarlo, teniendo en cuenta que la cantidad de elementos podría oscilar entre unos pocos y cientos?

+3

¿Considera secuencias '{1,1,2}' y '{1,2}' "equivalentes"? –

+0

@Mehrdad, Sí, me gustaría que se los considere iguales. – driis

+0

Por "conjuntos", ¿supongo que quiere decir que todos los elementos son únicos? – Kobi

Respuesta

100

Si desea tratar las matrices como "conjuntos" e ignorar el orden y duplicar los elementos, puede utilizar HashSet<T>.SetEquals method:

var isEqual = new HashSet<int>(first).SetEquals(second); 

De lo contrario, lo mejor es, probablemente, clasificando las dos secuencias de la misma manera y usando SequenceEqual para compararlos.

+1

Creo que HashSet .SetEquals era el método que estaba buscando :-) – driis

+0

Buena respuesta-- ¡Me olvidé de SetEquals! Si puede tener duplicados, antes de ordenarlos probablemente debería copiar las secuencias en una lista y comparar las longitudes primero; esto le ahorra las operaciones de clasificación (costosas) o SequenceEqual() en caso de que las longitudes sean diferentes. –

+2

@Justin Grant - No sigo ... Debe eliminar duplicados antes de comparar longitudes, y esto es tan costoso como ordenar. – Kobi

-1

Esto debería ayudar:

IEnumerable<int> data = new []{ 3,5,6,9 }; 
    IEnumerable<int> otherData = new[] {6, 5, 9, 3}; 

    if(data.All(x => otherData.Contains(x))) 
    { 
     //Code Goes Here 
    } 
+3

Es O (n²) en complejidad. Peligroso si tiene más de varias docenas de artículos en su lista. –

+0

Simple, pero esto no funcionará lo suficientemente bien para mi escenario. – driis

+4

Esto no se detectará si 'otherData' contiene elementos adicionales. –

3

Si es posible que tenga duplicados (o si desea una solución que funciona mejor para las listas más largas), me gustaría probar algo como esto:

static bool IsSame<T>(IEnumerable<T> set1, IEnumerable<T> set2) 
{ 
    if (set1 == null && set2 == null) 
     return true; 
    if (set1 == null || set2 == null) 
     return false; 

    List<T> list1 = set1.ToList(); 
    List<T> list2 = set2.ToList(); 

    if (list1.Count != list2.Count) 
     return false; 

    list1.Sort(); 
    list2.Sort(); 

    return list1.SequenceEqual(list2); 
} 

ACTUALIZACIÓN: ¡Ups, tienen razón, la solución Except() a continuación debe mirar a ambos lados antes de cruzar la calle. Y tiene un rendimiento pésimo para listas más largas. Ignora la sugerencia a continuación! :-)

Aquí hay una manera fácil de hacerlo. Tenga en cuenta que esto supone que las listas no tienen duplicados.

bool same = data.Except (otherData).Count() == 0; 
+3

Puede usar .Any() en lugar de Count() - entonces no enumerará todos los elementos en la lista. –

+4

¿Qué pasa si 'data = {1,2}, otherData = {1,2,3}'? También deberías verificar al revés. – Kobi

+0

Esto no funcionará en mi escenario, sin verificar las dos formas como lo sugiere Kobi. Y con unos pocos cientos de elementos, me preocuparía el rendimiento de ese enfoque. – driis

0
  1. En primer lugar, comprobar la longitud. Si son diferentes, los conjuntos son diferentes.
  2. puede hacer data.Intersect(otherData);, y compruebe que la longitud es idéntica.
  3. O bien, simplifique los conjuntos y repítelos.
+1

"data.Intersect (otherData), y compruebe que la longitud es idéntica" - debe asegurarse de que la longitud sea idéntica a AMBAS otras secuencias –

+0

@Mark - En el primer paso se suponía que debía verificar que ambos están en la misma longitud , entonces deberías estar bien. Eso no está escrito muy bien, estoy de acuerdo. (también, hablamos de la larga cola ... más de 2 años para obtener un comentario ':)') – Kobi

+0

Sí, eso es cierto. Comprobar la longitud tanto (ya que es IEnumerable) no es necesariamente factible, aunque se compara con la simple creación de un HashSet de la secuencia 1 y su comparación con la secuencia 2. Intersect básicamente hará esto de todos modos. –

41

Sugiero ordenar ambos y hacer una comparación elemento por elemento.

data.OrderBy(x => x).SequenceEqual(otherData.OrderBy(x => x)) 

no estoy seguro de la rapidez con la implementación de OrderBy es, pero si es un O (n log n) género como uno esperaría que el algoritmo total es O (n log n) también.

Para algunos casos de datos, puede mejorar esto mediante el uso de una implementación personalizada de OrderBy que, por ejemplo, utiliza una ordenación de conteo, para O (n + k), con k el tamaño del rango donde se encuentran los valores.

-1

En primer lugar comprobar si las dos colecciones de datos tienen el mismo número de elementos y la comprobación de si todos los elementos en una sola colección se presentan en la otra

 IEnumerable<int> data = new[] { 3, 5, 6, 9 }; 
     IEnumerable<int> otherData = new[] { 6, 5, 9, 3 }; 

     bool equals = data.Count() == otherData.Count() && data.All(x => otherData.Contains(x)); 
+0

Para una matriz regular, .Contains es O (N) y .All es también O (N), lo que hace que O (N^2). Las opciones basadas en clasificación y/o conjunto son mejores si su conjunto de datos no es trivialmente pequeño. – Pagefault

+0

Tampoco da la respuesta correcta si se permiten duplicados en la entrada. – Pagefault

2

Sé que esto es una vieja pregunta, pero aquí es otra manera para hacerlo

IEnumerable<int> data = new[] { 3, 5, 6, 9 };    
IEnumerable<int> otherData = new[] { 6, 5, 9, 3 }; 

data = data.OrderBy(d => d); 
otherData = otherData.OrderBy(d => d); 
data.Zip(otherData, (x, y) => Tuple.Create(x, y)).All(d => d.Item1 == d.Item2); 
+1

Su última línea es wring. Use 'var isEqual = data.Zip (otherData, (x, y) => x == y) .Todo (w => w)' en su lugar;). –

+0

@ shA, t ¿cómo es eso incorrecto int == int? Pude ver que ser un problema con una clase pero que no debería haber nada malo aquí –

+0

tu derecha, estaba usando una extensión interna antes de –

Cuestiones relacionadas