O .NET tem uma maneira de verificar se a Lista a contém todos os itens da Lista b?


97

Eu tenho o seguinte método:

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

O objetivo é determinar se uma lista contém todos os elementos de outra lista. Parece-me que algo assim já estaria integrado no .NET, é esse o caso e estou duplicando a funcionalidade?

Edit: Minhas desculpas por não declarar antecipadamente que estou usando este código no Mono versão 2.4.2.



Seu algoritmo é quadrático O (nm). Se as listas forem classificadas, testar se uma é um subconjunto de outra deve ser possível em tempo O (n + m).
— Coronel Panic

Respostas:


175

Se você estiver usando .NET 3.5, é fácil:

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

Isso verifica se há elementos nos bquais não estão a- e então inverte o resultado.

Observe que seria um pouco mais convencional tornar o método genérico em vez da classe, e não há razão para exigir em List<T>vez de IEnumerable<T>- então provavelmente seria preferível:

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

1
Isso não foi testado, mas não retornaria b.Except (a) .Empty (); ser muito mais legível?
— Nils

7
Exceto que Empty () não retorna um booleano. Ele retorna um IEnumerable <T> sem itens.
— Peter Stephens,

2
Você pode usar LINQ to Objects no Mono, eu acredito ... mas seria útil se você declarasse os requisitos na pergunta para começar. Qual versão do Mono você está usando?
— Jon Skeet

1
Se as listas têm comprimento n e m, qual é a complexidade de tempo desse algoritmo?
— Coronel Panic

1
@ColonelPanic: Supondo que não haja colisões de hash, O (n + m).
— Jon Skeet

37

Incluído no .NET 4: Enumerable.All

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

35

Apenas por diversão, a resposta de @JonSkeet como um método de extensão:

/// <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
da mesma forma: Contains Any = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. Eu tentei algumas comparações rápidas de desempenho haystack.Count() - 1 >= haystack.Except(needle).Count();e Intersectparecia me sair melhor na maioria das vezes.
— drzaus

4
sheesh ... Any()não use Count() > 0: public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Any(); }
— drzaus

0

Você também pode usar outra maneira. Substituir igual e usar este

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);Eu não acho que isso iria compilar e se o fizer, é totalmente desnecessário, pois checkjá é uma lista
— Rohit Vipin Mathews
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.