2009-10-05 19 views
68

Mam następujący sposób:Czy .NET ma sposób sprawdzenia, czy lista a zawiera wszystkie elementy na liście b?

namespace ListHelper 
{ 
    public class ListHelper<T> 
    { 
     public static bool ContainsAllItems(List<T> a, List<T> b) 
     { 
      return b.TrueForAll(delegate(T t) 
      { 
       return a.Contains(t); 
      }); 
     } 
    } 
} 

którego celem jest ustalenie, czy lista zawiera wszystkie elementy innej listy. Wydaje mi się, że coś takiego zostanie wbudowane w .NET, czy tak jest i czy duplikuję funkcjonalność?

Edytuj: Przepraszam, że nie stwierdziłem z góry, że używam tego kodu w wersji Mono 2.4.2.

+0

Zobacz również https://stackoverflow.com/questions/332973/check-whether-an-array-is-a -subset-of-another –

+0

Twój algorytm to kwadrat O (nm). Jeśli listy są posortowane, sprawdzenie, czy jedna z nich jest podzbiorem innej, powinno być możliwe w czasie O (n + m). –

Odpowiedz

126

Jeśli używasz .NET 3.5, to proste:

public class ListHelper<T> 
{ 
    public static bool ContainsAllItems(List<T> a, List<T> b) 
    { 
     return !b.Except(a).Any(); 
    } 
} 

ten sprawdza, czy są jakieś elementy b, które nie są w a - a potem odwraca wynik.

Zauważ, że byłoby nieco bardziej konwencjonalny, aby metodę rodzajowe zamiast klasy, i nie ma powodu, aby wymagać List<T> zamiast IEnumerable<T> - tak to będzie prawdopodobnie preferowane:

public static class LinqExtras // Or whatever 
{ 
    public static bool ContainsAllItems<T>(IEnumerable<T> a, IEnumerable<T> b) 
    { 
     return !b.Except(a).Any(); 
    } 
} 
+0

To jest niesprawdzone, ale nie zwróci b.Oczekiwacza (a) .Empty(); być o wiele bardziej czytelny? – Nils

+7

Poza tym, że Empty() nie zwraca wartości boolowskiej. Zwraca IEnumerable bez żadnych elementów. –

+0

To wymaga Linq w prawo? Jeśli tak, nie sądzę, że jest to dostępne w Mono, w tym właśnie używam. –

29

Wystarczy dla zabawy, @ JonSkeet na answer jako metodę rozszerzenia:

/// <summary> 
/// Does a list contain all values of another list? 
/// </summary> 
/// <remarks>Needs .NET 3.5 or greater. Source: https://stackoverflow.com/a/1520664/1037948 </remarks> 
/// <typeparam name="T">list value type</typeparam> 
/// <param name="containingList">the larger list we're checking in</param> 
/// <param name="lookupList">the list to look for in the containing list</param> 
/// <returns>true if it has everything</returns> 
public static bool ContainsAll<T>(this IEnumerable<T> containingList, IEnumerable<T> lookupList) { 
    return ! lookupList.Except(containingList).Any(); 
} 
+2

+1 za dodatkową pracę – jeremy

+2

podobnie: Zawiera Dowolne = 'publiczny statyczny sygnał logiczny Zawiera(ten IEnumerable stóg siana, IEnumerable igła) {return haystack.Intersect (needle) .Count()> 0; } '. Próbowałem kilka szybkich porównań wydajności do 'haystack.Count() - 1> = haystack.Except (needle) .Count();' i 'Intersect' wydawał się lepiej przez większość czasu. – drzaus

+3

sheesh ... użyj 'Any()' not 'Count()> 0':' public static bool ContainsAny (this IEnumerable needle) {return haystack.Intersect (needle).Każdy(); } ' – drzaus

0

można także użyć w inny sposób. Przesłanianie równa się i korzystać z tego

public bool ContainsAll(List<T> a,List<T> check) 
{ 
    list l = new List<T>(check); 
    foreach(T _t in a) 
    { 
     if(check.Contains(t)) 
     { 
     check.Remove(t); 
     if(check.Count == 0) 
     { 
      return true; 
     } 
     } 
     return false; 
    } 
} 
+2

' lista l = nowa lista (czek); 'Nie sądzę, że to by się skompilowało, a jeśli tak, to zupełnie niepotrzebne jako' czek' jest już listą –

13

wliczony w .NET 4: Enumerable.All

public static bool ContainsAll<T>(IEnumerable<T> source, IEnumerable<T> values) 
{ 
    return values.All(value => source.Contains(value)); 
} 
Powiązane problemy