Vérifier si un IEnumerable contient tous les éléments d’un autre IEnumerable

Quel est le moyen le plus rapide de déterminer si un IEnumerable contient tous les éléments d’un autre IEnumerable lors de la comparaison d’un champ / propriété de chaque élément dans les deux collections?


public class Item { public ssortingng Value; public Item(ssortingng 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 list1, IEnumerable, 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 

    Il n’y a pas de “moyen rapide” de le faire, sauf si vous suivez et conservez un état qui détermine si toutes les valeurs d’une collection sont contenues dans une autre. Si vous n’avez que IEnumerable contre, j’utiliserais Intersect .

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

    Les performances devraient être très raisonnables, car Intersect() énumérera une seule fois chaque liste. De plus, le deuxième appel à Count() sera optimal si le type sous-jacent est un ICollection plutôt qu’un IEnumerable .

    Vous pouvez également utiliser Except pour supprimer de la première liste toutes les valeurs de la deuxième liste, puis vérifier si toutes les valeurs ont été supprimées:

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

    Cette méthode avait l’avantage de ne pas nécessiter deux appels à Count ().

    C # 3.5+

    Enumerable.All pour déterminer si tous les éléments List2 sont contenus dans List1:

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

    Cela fonctionnera également lorsque list1 contient encore plus que tous les éléments de list2.

    La solution marquée comme réponse échouerait en cas de répétitions. Si votre IEnumerable ne contenait que des valeurs distinctes, il passerait.

    La réponse ci-dessous est pour 2 listes avec des répétitions:

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

    La réponse de Kent est fine et courte, mais la solution qu’il propose nécessite toujours une itération sur toute la première collection. Voici le code source:

     public static IEnumerable Intersect(this IEnumerable first, IEnumerable second, IEqualityComparer comparer) { if (first == null) throw Error.ArgumentNull("first"); if (second == null) throw Error.ArgumentNull("second"); return Enumerable.IntersectIterator(first, second, comparer); } private static IEnumerable IntersectIterator(IEnumerable first, IEnumerable second, IEqualityComparer comparer) { Set set = new Set(comparer); foreach (TSource source in second) set.Add(source); foreach (TSource source in first) { if (set.Remove(source)) yield return source; } } 

    Ce n’est pas toujours nécessaire. Alors voici ma solution:

     public static bool Contains(this IEnumerable source, IEnumerable subset, IEqualityComparer comparer) { var hashSet = new HashSet(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 fait, vous devriez penser à utiliser ISet ( HashSet ). Il contient toutes les méthodes de configuration requirejses. IsSubsetOf dans votre cas.

    L’opérateur Linq SequenceEqual fonctionnerait également (mais est sensible aux éléments de l’énumérateur étant dans le même ordre)

     return list1Uris.SequenceEqual(list2Uris); 

    Vous devez utiliser HashSet au lieu de Array.

    Exemple:

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

    Référence

    La seule limitation de HasSet est que nous ne pouvons pas obtenir d’élément par index comme List, ni obtenir d’élément par Key comme des dictionnaires. Tout ce que vous pouvez faire est de les énumérer (pour chacun, pendant tout, etc.)

    S’il vous plaît laissez-moi savoir si cela fonctionne pour vous

    vous pouvez utiliser cette méthode pour comparer deux liste

      //Method to compare two list private bool Contains(IEnumerable list1, IEnumerable 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; }