Есть ли в .NET способ проверить, содержит ли список a все элементы списка b?


98

У меня есть такой способ:

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

Цель этого метода - определить, содержит ли список все элементы другого списка. Мне кажется, что что-то подобное уже встроено в .NET, так ли это, и дублирую ли я функциональность?

Изменить: приношу свои извинения за то, что не сказал заранее, что я использую этот код в Mono версии 2.4.2.



Ваш алгоритм является квадратичным O (нм). Если списки отсортированы, проверка того, является ли один из них подмножеством другого, должна быть возможна за O (n + m) раз.
Полковник Паник

Ответы:


177

Если вы используете .NET 3.5, это просто:

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

Это проверяет, есть ли какие-либо элементы, bкоторых нет, aи затем инвертирует результат.

Обратите внимание, что было бы немного более традиционным сделать метод универсальным, а не классом, и нет причин требовать List<T>вместо IEnumerable<T>- так что это, вероятно, будет предпочтительнее:

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

1
Это не проверено, но не вернет b.Except (a) .Empty (); быть более читаемым?
Нильс

7
За исключением того, что Empty () не возвращает логическое значение. Он возвращает IEnumerable <T> без элементов.
Питер Стивенс

2
Я считаю, что вы можете использовать LINQ to Objects в Mono ... но было бы полезно, если бы вы для начала указали требования в вопросе. Какую версию Mono вы используете?
Джон Скит

1
Если списки имеют длину n и m, какова временная сложность этого алгоритма?
Colonel Panic

1
@ColonelPanic: при отсутствии хеш-коллизий O (n + m).
Джон Скит

38

Включено в .NET 4: Enumerable.All

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

35

Просто для удовольствия, ответ @JonSkeet как метод расширения:

/// <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
аналогично: содержит Any = public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Count() > 0; }. Я попробовал несколько быстрых сравнений производительности haystack.Count() - 1 >= haystack.Except(needle).Count();и, Intersectпохоже, большую часть времени у меня получалось лучше.
drzaus

4
шиш ... Any()не используйте Count() > 0: public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Any(); }
drzaus 04

0

Вы также можете использовать другой способ. Переопределить равно и использовать это

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);Я не думаю, что это будет компилироваться, и если это произойдет, в этом нет необходимости, так как checkэто уже список
Рохит Випин Мэтьюз,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.