Est-ce que .NET a un moyen de vérifier si la liste a contient tous les éléments de la liste b?

98

J'ai la méthode suivante:

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

Le but est de déterminer si une liste contient tous les éléments d'une autre liste. Il me semble que quelque chose comme celui-ci serait déjà intégré à .NET, est-ce le cas et est-ce que je duplique la fonctionnalité?

Edit: Mes excuses pour ne pas avoir déclaré à l'avance que j'utilise ce code sur la version 2.4.2 Mono.

Matt Haley
la source
Voir aussi stackoverflow.com/questions/332973/…
Colonel Panic
Votre algorithme est quadratique O (nm). Si les listes sont triées, tester si l'une est un sous-ensemble d'une autre devrait être possible en un temps O (n + m).
Colonel Panic

Réponses:

176

Si vous utilisez .NET 3.5, c'est simple:

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

Cela vérifie s'il y a des éléments dans blesquels ne figurent pas a- puis inverse le résultat.

Notez qu'il serait légèrement plus conventionnel de rendre la méthode générique plutôt que la classe, et il n'y a aucune raison d'exiger à la List<T>place de IEnumerable<T>- donc ce serait probablement préférable:

public static class LinqExtras // Or whatever
{
    public static bool ContainsAllItems<T>(this IEnumerable<T> a, IEnumerable<T> b)
    {
        return !b.Except(a).Any();
    }
}
Jon Skeet
la source
1
Ceci n'est pas testé, mais ne retournerait pas b.Except (a) .Empty (); être beaucoup plus lisible?
Nils
7
Sauf que Empty () ne renvoie pas de booléen. Il renvoie un IEnumerable <T> sans élément.
Peter Stephens
2
Vous pouvez utiliser LINQ to Objects en Mono, je crois ... mais il serait utile que vous indiquiez les exigences dans la question pour commencer. Quelle version de Mono utilisez-vous?
Jon Skeet
1
Si les listes sont de longueur n et m, quelle est la complexité temporelle de cet algorithme?
Colonel Panic
1
@ColonelPanic: En supposant qu'il n'y a pas de collisions de hachage, O (n + m).
Jon Skeet
37

Inclus dans .NET 4: Enumerable.All

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

Juste pour le plaisir, la réponse de @ JonSkeet comme méthode d'extension:

/// <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();
}
drzaus
la source
2
de même: Contient Any = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. J'ai essayé quelques comparaisons rapides de performances haystack.Count() - 1 >= haystack.Except(needle).Count();et j'ai Intersectsemblé faire mieux la plupart du temps.
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

Vous pouvez également utiliser une autre méthode. Remplacer égal et utiliser ceci

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;
   }
}
user3210251
la source
2
list l = new List<T>(check);Je ne pense pas que cela compilerait et si c'est le cas, c'est totalement inutile, car checkc'est déjà une liste
Rohit Vipin Mathews