.NET有没有一种方法可以检查List a是否包含List b中的所有项?

118
我有以下方法:

我有以下方法:

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

该目的是确定一个List是否包含另一个List的所有元素。看起来像这样的功能已经内置于.NET中了,那么情况是这样的吗?我是否在重复使用功能?

编辑:很抱歉我没有提前说明我正在使用Mono版本2.4.2上的代码。


请参见 https://dev59.com/pXRC5IYBdhLWcg3wVvYt - Colonel Panic
你的算法是二次的O(nm)。如果列表已排序,则测试一个是否为另一个子集应该在O(n+m)时间内完成。 - Colonel Panic
5个回答

207

如果你正在使用.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
这个还没有经过测试,但是使用 return b.Except(a).Empty(); 不是更易读吗? - Nils
7
除了Empty()不返回布尔值之外,它返回一个没有任何项的IEnumerable<T>。 - Peter Stephens
2
你可以在Mono中使用LINQ to Objects,我相信...但如果你一开始就说明要求,那会更有帮助。你使用的是哪个版本的Mono? - Jon Skeet
1
如果列表的长度分别为n和m,那么这个算法的时间复杂度是多少? - Colonel Panic
1
@ColonelPanic:假设没有哈希冲突,时间复杂度为O(n+m)。 - Jon Skeet
显示剩余4条评论

48

.NET 4 中包含:Enumerable.All

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

Enumerable.All 在 .Net 4.0 之前就存在了,这里它是一个 O(N^2) 的操作 被接受的答案中的操作相反。 - undefined

36

仅为娱乐,@JonSkeet的回答作为扩展方法:

/// <summary>
/// Does a list contain all values of another list?
/// </summary>
/// <remarks>Needs .NET 3.5 or greater.  Source:  https://dev59.com/knI_5IYBdhLWcg3wHfOr#1520664 </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
类似于:包含任何 = 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() > 0public static bool ContainsAny<T>(this IEnumerable<T> haystack, IEnumerable<T> needle) { return haystack.Intersect(needle).Any(); } - drzaus

3

我知道一种使用LinQ方法的方法。虽然读起来有点奇怪,但效果相当不错。

var motherList = new List<string> { "Hello", "World", "User };
var sonList = new List<string> { "Hello", "User" };

您想要检查sonList是否完全包含在motherList中

操作步骤如下:

sonList.All(str => moterList.Any(word => word == str));

// Reading literally, would be like "For each of all items 
// in sonList, test if it's in motherList

请打开并查看是否在那里也有效。希望能帮到你;-)

这个是有效的。但请纠正这行代码中的拼写错误: bool result = sonList.All(str => motherList.Any(word => word == str)); - Shubhjot

-1

你也可以使用另一种方式。覆盖equals方法并使用this。

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<T> l = new List<T>(check); 我认为这段代码不会编译,即使它能够编译通过,也是完全没有必要的,因为 check 已经是一个列表了。 - Rohit Vipin Mathews

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接