.NET ha un modo per verificare se List a contiene tutti gli elementi in List b?


98

Ho il seguente metodo:

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 è determinare se una lista contiene tutti gli elementi di un'altra lista. Mi sembra che qualcosa di simile sia già integrato in .NET, è così e sto duplicando la funzionalità?

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



Il tuo algoritmo è quadratico O (nm). Se gli elenchi sono ordinati, dovrebbe essere possibile verificare se uno è un sottoinsieme di un altro in tempo O (n + m).
Colonel Panic

Risposte:


176

Se stai usando .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 bcui non sono presenti ae quindi inverte il risultato.

Nota che sarebbe leggermente più convenzionale rendere il metodo generico piuttosto che la classe, e non c'è motivo di richiedere List<T>invece di IEnumerable<T>- quindi questo sarebbe probabilmente preferito:

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

1
Non è stato testato, ma non restituirebbe b.Except (a) .Empty (); essere molto più leggibile?
Nils

7
Tranne che Empty () non restituisce un valore booleano. Restituisce un IEnumerable <T> senza elementi.
Peter Stephens,

2
Puoi usare LINQ to Objects in Mono, credo ... ma sarebbe utile se indicassi i requisiti nella domanda per iniziare. Quale versione di Mono stai usando?
Jon Skeet,

1
Se le liste sono di lunghezza n e m, qual è la complessità temporale di questo algoritmo?
Colonel Panic

1
@ColonelPanic: supponendo che non ci siano collisioni di hash, O (n + m).
Jon Skeet

37

Incluso in .NET 4: Enumerable.All

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

35

Solo per divertimento, la risposta di @ JonSkeet come 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
allo stesso modo: contiene qualsiasi = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. Ho provato alcuni rapidi confronti delle prestazioni haystack.Count() - 1 >= haystack.Except(needle).Count();e mi è Intersectsembrato di fare meglio la maggior parte del tempo.
drzaus

4
sheesh ... Any()non usare Count() > 0: public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Any(); }
drzaus

0

Potresti anche usare un altro modo. Sostituisci uguale e usa 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
list l = new List<T>(check);Non penso che questo si compilerebbe e se lo fa, è totalmente inutile in quanto checkè già un elenco
Rohit Vipin Mathews
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.