2009-10-05 10 views
68

Ho il seguente metodo:.NET ha un modo per verificare se l'Elenco a contiene tutti gli elementi in Elenco 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); 
      }); 
     } 
    } 
} 

Lo scopo è quello di determinare se un elenco contiene tutti gli elementi di un altro elenco. Mi sembra che qualcosa di simile sarebbe già stato incorporato in .NET, è il caso e sto duplicando funzionalità?

Modifica: Le mie scuse per non aver dichiarato in anticipo che sto usando questo codice su Mono versione 2.4.2.

+0

Vedi anche https://stackoverflow.com/questions/332973/check-whether-an-array-is-a -subset-of-another –

+0

L'algoritmo è quadratico O (nm). Se gli elenchi sono ordinati, è possibile testare se uno è un sottoinsieme di un altro nel tempo O (n + m). –

risposta

126

Se si sta utilizzando .NET 3.5, è facile:

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

Questo controlla se ci sono elementi in b che non sono in a - e poi inverte il risultato.

Nota che sarebbe stato un po 'più convenzionale per rendere il metodo generico piuttosto che la classe, e non c'è motivo di esigere List<T> invece di IEnumerable<T> - quindi questo sarebbe probabilmente preferibile:

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

Questo non è verificato, ma non sarebbe return b.Except (a) .Empty(); essere molto più leggibile? – Nils

+7

Tranne che Empty() non restituisce un valore booleano. Restituisce un oggetto IEnumerable senza elementi. –

+0

Ciò richiede Linq, giusto? Se è così, non penso che sia disponibile in Mono, che è quello che sto usando al momento. –

29

Proprio per divertimento, @ JonSkeet di answer come un metodo di estensione:

/// <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 per il lavoro aggiuntivo – jeremy

+2

in modo simile: contiene Any = 'public static bool ContainsAny (questo pagliaio IEnumerable , IEnumerable ) {return haystack.Intersect (needle) .Count()> 0; } '. Ho provato alcuni raffronti rapidi delle prestazioni con 'haystack.Count() - 1> = haystack.Except (needle) .Count();' e 'Intersect' sembrava fare meglio la maggior parte del tempo. – drzaus

+3

sheesh ... usa 'Any()' non 'Count()> 0':' public static bool ContainsAny (questo IEnumerable haystack, IEnumerable needle) {return haystack.Intersect (needle).Qualunque(); } ' – drzaus

0

Si potrebbe anche usare un altro modo. Override è uguale e utilizzare questo

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 = nuova lista (verifica); 'Non penso che questo sarebbe compilato e se lo fa, è assolutamente inutile come' check' è già una lista –

13

Incluso nel .NET 4: Enumerable.All

public static bool ContainsAll<T>(IEnumerable<T> source, IEnumerable<T> values) 
{ 
    return values.All(value => source.Contains(value)); 
} 
Problemi correlati