【问题标题】:Determine if a sequence contains all elements of another sequence using Linq [duplicate]使用Linq确定一个序列是否包含另一个序列的所有元素[重复]
【发布时间】:2009-01-02 19:02:48
【问题描述】:

给定两组值:

var subset = new[] { 2, 4, 6, 8 };

var superset = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

如何确定superset 是否包含subset 的所有元素?

我想出了这个:

superset.Intersect(subset).Count() == subset.Count()

这是最合乎逻辑和最有效的方法吗?

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    计数? Not Any 怎么样?

    bool contained = !subset.Except(superset).Any();
    

    【讨论】:

    • +1 Any() 比 Count() 效率高很多
    • 比计数好得多。如果我没记错的话,这也会在找到第一个不匹配项时停止。
    【解决方案2】:

    所以,我的另一个答案很容易使用。但这是一个 O(n*m) 的解决方案。

    这是一个稍微不太友好的 O(n+m) 解决方案。如果超集很大,应该使用这个。它避免了重复枚举超集。

    HashSet<int> hashSet = new HashSet<int>(superset);
    bool contained = subset.All(i => hashSet.Contains(i));
    

    【讨论】:

    【解决方案3】:

    我有一个使用现有 Contains() 方法的扩展方法。我发现它比使用 Instersect() 或 except() 更直观。

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

    【讨论】:

    • 这可能会为每个value 处理source 的所有值,这可能会非常昂贵。 Except 解决方案只对每个源值和目标值进行一次处理,使其成为整体上更高效的解决方案。
    • @BryanWatts,我还没有“深入了解”LINQ 如何优化这些不同的查询方法。但是,如果我们想象最简单的实现,这两种解决方案不是完全相等吗?例外解决方案需要迭代所有“子集”元素,并为每个值迭代“超集”(除非 LINQ 以某种方式对其进行了优化)。
    • 语义上它们是相等的:它们将为相同的输入产生相同的输出。然而,Except 的 LINQ 实现迭代源序列一次,存储值(我认为是一个哈希集),然后迭代目标序列一次,从集合中删除它的项目。 LINQ 针对最小迭代进行了大量优化。
    • 我明白了。而且我想 LINQ 通常更容易优化“纯”查询,而其中没有 Lambda 表达式。不过还是喜欢我的可读性:-)
    • LINQ 通常会针对最小迭代进行优化,即使对于带有 lambda 表达式的方法,例如 OrderBy。现在,您在这些 lambda 表达式中执行的操作可能非常低效,但这取决于您 :-) 我也喜欢您的可读性;我正在考虑使用 Except 实现添加您的扩展方法,以获得两全其美。
    【解决方案4】:

    你可以使用 except,结果计数应该是 0。

    在 MSDN 上阅读参数的详细信息。

    例子:

    subset.Except(superset).Count() == 0
    

    【讨论】:

    • 执行 !Any() 与 Count() == 0 相比效率更高。Count() 将遍历整个可枚举,而 Any() 将只查找第一个元素。跨度>
    猜你喜欢
    • 2015-02-08
    • 1970-01-01
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多