2010-07-18 17 views
65

¿Cuál es la forma más rápida de determinar si un elemento de IEnumerable contiene todos los elementos de otro IEnumerable al comparar un campo/propiedad de cada elemento en ambas colecciones?Compruebe si un elemento de IEnumerable contiene todos los elementos de otro IEnumerable


public class Item 
{ 
    public string Value; 

    public Item(string value) 
    { 
     Value = value; 
    } 
} 

//example usage 

Item[] List1 = {new Item("1"),new Item("a")}; 
Item[] List2 = {new Item("a"),new Item("b"),new Item("c"),new Item("1")}; 

bool Contains(IEnumerable<Item> list1, IEnumerable<Item>, list2) 
{ 
    var list1Values = list1.Select(item => item.Value); 
    var list2Values = list2.Select(item => item.Value); 

    return //are ALL of list1Values in list2Values? 
} 

Contains(List1,List2) // should return true 
Contains(List2,List1) // should return false 
+1

Qué inversa son sus listas? ¿Desea verificar si todos los elementos de la lista1 están en la lista 2 o si todos los elementos de la lista 2 están en la lista 1? –

Respuesta

94

No hay una "forma rápida" de hacerlo a menos que rastree y mantenga algún estado que determine si todos los valores en una colección están contenidos en otra. Si solo tiene IEnumerable<T> para trabajar en contra, usaría Intersect.

var allOfList1IsInList2 = list1.Intersect(list2).Count() == list1.Count(); 

El rendimiento de este debe ser muy razonable, ya que Intersect() enumerará sobre cada lista sólo una vez. Además, la segunda llamada al Count() será óptima si el tipo subyacente es ICollection<T> en lugar de solo IEnumerable<T>.

+0

Hice algunas pruebas y este método parece ejecutarse más rápido que los demás. Gracias por el consejo. –

+0

Creo que te refieres a 'var allOfList2IsInList1 = list1.Intersect (list2) .Count() == list2.Count();' – dan

+2

@fsmmu: no, no lo hice. La primera llamada busca cuántos elementos se encuentran en la intersección de las listas 1 y 2. La segunda llamada busca cuántos elementos hay en la lista 1. Si esos números son iguales, entonces toda la lista 1 está en la lista 2, según los OP. pregunta. –

2

la SequenceEqual operador LINQ funcionaría también (pero es sensible a los elementos de la enumerables estar en el mismo orden)

return list1Uris.SequenceEqual(list2Uris); 
18

C# 3.5 +

Usando Enumerable.All<TSource> para determinar si todos los elementos de List2 se incluyen en List1:

bool hasAll = list2Uris.All(itm2 => list1Uris.Contains(itm2)); 

Esto también funcionará cuando list1 contenga incluso más que todos los elementos de list2.

+8

Ouch en implicaciones de rendimiento de una llamada 'Contains()' dentro de una llamada 'All()'. –

+0

También puede moverlo al método de grupo: bool hasAll = list2Uris.All (list1Uris.Contains); – jimpanzer

+0

I caso de IEnumerable tipos de esta solución proporcionará n * m de rendimiento. –

31

También es posible usar Excepto para eliminar de la primera lista de todos los valores que existen en la segunda lista, y luego comprobar si todos los valores se han eliminado:

var allOfList1IsInList2 = !list1.Except(list2).Any(); 

Este método tiene la ventaja de no requerir dos llamadas a Count().

+0

Esto también es bueno para descubrir lo que está en la Lista1 pero no en la Lista2; – Homer

+5

Esto funciona en situaciones donde list1 tiene valores duplicados. La respuesta aceptada no. – dbc

4

La solución marcada como la respuesta fallaría en el caso de repeticiones. Si su IEnumerable solo contiene valores distintos, entonces pasaría.

La respuesta a continuación es para 2 listas con repeticiones:

 int aCount = a.Distinct().Count(); 
     int bCount = b.Distinct().Count(); 

     return aCount == bCount && 
       a.Intersect(b).Count() == aCount; 
3

respuesta de Kent es fino y corto, pero la solución que ofrece siempre requiere iteración sobre toda la primera colección. Aquí está el código fuente:

public static IEnumerable<TSource> Intersect<TSource>(this IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 
{ 
    if (first == null) 
     throw Error.ArgumentNull("first"); 
    if (second == null) 
     throw Error.ArgumentNull("second"); 
    return Enumerable.IntersectIterator<TSource>(first, second, comparer); 
} 

private static IEnumerable<TSource> IntersectIterator<TSource>(IEnumerable<TSource> first, IEnumerable<TSource> second, IEqualityComparer<TSource> comparer) 
{ 
    Set<TSource> set = new Set<TSource>(comparer); 
    foreach (TSource source in second) 
     set.Add(source); 
    foreach (TSource source in first) 
    { 
     if (set.Remove(source)) 
      yield return source; 
    } 
} 

Eso no siempre es necesario. Por lo tanto, aquí está mi solución:

public static bool Contains<T>(this IEnumerable<T> source, IEnumerable<T> subset, IEqualityComparer<T> comparer) 
{ 
    var hashSet = new HashSet<T>(subset, comparer); 
    if (hashSet.Count == 0) 
    { 
     return true; 
    } 

    foreach (var item in source) 
    { 
     hashSet.Remove(item); 
     if (hashSet.Count == 0) 
     { 
      break; 
     } 
    } 

    return hashSet.Count == 0; 
} 

En realidad, usted debe pensar en usar ISet<T> (HashSet<T>). Contiene todos los métodos de conjunto requeridos. IsSubsetOf en su caso.

-1

se puede utilizar este método para comparar dos listas

//Method to compare two list 
    private bool Contains(IEnumerable<Item> list1, IEnumerable<Item> list2) 
    { 
     bool result; 

     //Get the value 
     var list1WithValue = list1.Select(s => s.Value).ToList(); 
     var list2WithValue = list2.Select(s => s.Value).ToList(); 

     result = !list1WithValue.Except(list2WithValue).Any(); 

     return result; 
    } 
+0

Casi la misma respuesta se dio 3 años antes: http://stackoverflow.com/a/16967827/5282087 – Dragomok

0

Debe utilizar HashSet en lugar de la matriz.

Ejemplo:

List1.SetEquals(List2); //returns true if the collections contains exactly same elements no matter the order they appear in the collection 

Reference

La única limitación es que Hasset no podemos conseguir el artículo por índice como lista, ni tampoco conseguir elemento clave como por Diccionarios. Todo lo que se puede hacer es enumerarlos (para cada uno, mientras que, etc)

Por favor, hágamelo saber si funciona para usted

Cuestiones relacionadas