2010-07-18 12 views
65

Was ist der schnellste Weg zu bestimmen, ob ein IEnumerable alle Elemente eines anderen IEnumerable enthält, wenn ein Feld/Eigenschaft jedes Elements in beiden Sammlungen verglichen wird?Überprüfen, ob ein IEnumerable alle Elemente eines anderen IEnumerable enthält


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

Welche Art und Weise rund sind Ihre Listen funktioniert? Möchten Sie überprüfen, ob sich alle Elemente in Liste1 in Liste 2 befinden oder alle Elemente in Liste2 in Liste 1 enthalten sind? –

Antwort

94

Es gibt keinen "schnellen Weg", dies zu tun, es sei denn, Sie verfolgen und pflegen einen Zustand, der bestimmt, ob alle Werte in einer Sammlung in einer anderen enthalten sind. Wenn Sie nur gegen IEnumerable<T> arbeiten, würde ich Intersect verwenden.

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

Die Leistung sollte dies sehr sinnvoll sein, da Intersect() nur einmal in jeder Liste aufzählen übernimmt. Auch der zweite Aufruf an Count() wird optimal sein, wenn der zugrunde liegende Typ ein ist und nicht nur ein IEnumerable<T>.

+0

Ich habe einige Tests durchgeführt und diese Methode scheint schneller zu laufen als die anderen. Danke für den Tipp. –

+0

Ich denke du meinst 'var allOfList2IsInList1 = list1.Intersect (list2) .Count() == list2.Count();' – dan

+2

@ fsmmu: nein, habe ich nicht. Der erste Aufruf findet heraus, wie viele Elemente sich in der Schnittmenge der Listen 1 und 2 befinden. Der zweite Aufruf findet, wie viele Elemente in der Liste 1 sind. Wenn diese Nummern gleich sind, befindet sich die gesamte Liste 1 gemäß OP in Liste 2 Frage. –

2

der Linq Betreiber SequenceEqual würde auch (aber empfindlich auf die Elemente des enumerable in der gleichen Reihenfolge zu sein)

return list1Uris.SequenceEqual(list2Uris); 
18

C# 3.5+

Enumerable.All<TSource> verwenden, wenn zu bestimmen, Alle List2-Elemente sind in Liste1 enthalten:

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

Dies funktioniert auch, wenn list1 noch mehr als alle Elemente von list2 enthält.

+8

Ouch bei der Leistung eines 'Contains()' Aufrufs innerhalb eines 'All()' Aufrufs. –

+0

Auch Sie können es in die Gruppenmethode verschoben werden: bool hasAll = list2Uris.All (list1Uris.Contains); – jimpanzer

+0

I Fall von IEnumerable Typen diese Lösung bietet n * m Leistung. –

31

Sie auch Ausgenommen von der ersten Liste alle Werte, die in der zweiten Liste vorhanden ist, und dann prüfen, ob alle Werte entfernt wurden, zu entfernen verwenden:

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

Dieses Verfahren hatte den Vorteil, nicht zwei erfordern ruft Count() auf.

+0

Dies ist auch gut für das Herausfinden, was in List1, aber nicht in List2 ist; – Homer

+5

Dies funktioniert in Situationen, in denen list1 doppelte Werte enthält. Die angenommene Antwort nicht. – dbc

4

Die als Antwort markierte Lösung würde bei Wiederholungen fehlschlagen. Wenn Ihr IEnumerable nur bestimmte Werte enthält, würde es bestehen.

Die unten Antwort ist für 2 Listen mit Wiederholungen:

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

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

Kent Antwort ist fein und kurz, aber die Lösung, die er immer Iteration über die gesamte erste Kollektion erfordert zur Verfügung stellt. Hier ist der Quellcode:

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; 
    } 
} 

Das ist nicht immer erforderlich. So, hier ist meine Lösung:

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; 
} 

Eigentlich sollte man denken, über die Verwendung von ISet<T> (HashSet<T>). Es enthält alle erforderlichen Mengenmethoden. IsSubsetOf in Ihrem Fall.

-1

können Sie diese Methode verwenden, um zwei Liste

//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

Ziemlich die gleiche Antwort wurde 3 Jahre zuvor gegeben: http://Stackoverflow.com/a/16967827/5282087 – Dragomok

0

Sie sollten verwenden HashSet statt Array zu vergleichen.

Beispiel:

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

Reference

Die einzige Hasset Einschränkung ist, dass wir nicht durch Artikel-Index wie List erhalten können noch Artikel von Key wie Wörterbücher erhalten. Alles, was Sie tun können, ist, sie aufzuzählen (für jeden, während usw.)

Sie mich bitte, wenn das für Sie

Verwandte Themen