¿Tiene .NET una forma de comprobar si la Lista a contiene todos los elementos de la Lista b?


98

Tengo el siguiente 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);
            });
        }
    }
}

El propósito de esto es determinar si una lista contiene todos los elementos de otra lista. Me parece que algo como esto ya estaría integrado en .NET, ¿es ese el caso y estoy duplicando la funcionalidad?

Editar: Mis disculpas por no decir desde el principio que estoy usando este código en Mono versión 2.4.2.



Su algoritmo es cuadrático O (nm). Si las listas están ordenadas, debería ser posible probar si una es un subconjunto de otra en O (n + m) tiempo.
Coronel Panic

Respuestas:


176

Si está utilizando .NET 3.5, es fácil:

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

Esto comprueba si hay elementos en los bque no están aincluidos y luego invierte el resultado.

Tenga en cuenta que sería un poco más convencional hacer que el método sea genérico en lugar de la clase, y no hay razón para requerir en List<T>lugar de IEnumerable<T>, por lo que probablemente sea preferible:

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

1
Esto no está probado, pero no devolvería b.Except (a) .Empty (); ser mucho más legible?
Nils

7
Excepto que Empty () no devuelve un booleano. Devuelve un IEnumerable <T> sin elementos.
Peter Stephens

2
Puede usar LINQ to Objects en Mono, creo ... pero sería útil si estableciera los requisitos en la pregunta para comenzar. ¿Qué versión de Mono estás usando?
Jon Skeet

1
Si las listas son de longitud nym, ¿cuál es la complejidad temporal de este algoritmo?
Coronel Panic

1
@ColonelPanic: Suponiendo que no hay colisiones hash, O (n + m).
Jon Skeet

37

Incluido en .NET 4: Enumerable.All

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

35

Solo por diversión, la respuesta de @ JonSkeet como método de extensión:

/// <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
de manera similar: Contiene Any = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. Probé algunas comparaciones rápidas de rendimiento haystack.Count() - 1 >= haystack.Except(needle).Count();y Intersectpareció hacerlo mejor la mayor parte del tiempo.
drzaus

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

0

También podría utilizar otra forma. Anule los iguales y use esto

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);No creo que esto se compile y, si lo hace, es totalmente innecesario, ya checkque ya es una lista
Rohit Vipin Mathews
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.