检查两个枚举之间是否存在一个共同元素的最快方法

本文关键字:元素 方法 一个 存在 两个 枚举 之间 检查 是否 | 更新日期: 2023-09-27 17:58:52

我有一个正在编写的方法,我希望能够根据订单中是否有一个或多个用户在选择产品时订购的产品来筛选订单。目前我正在使用:

SelectedProductIDs.Intersect(orderProductIDs).Any()

对每个订单执行(数据库中总共约20000个订单,预计会快速增长),其中SelectedProducts和orderProductID都是string[]。我还尝试为SelectedProductID和orderProductID使用预先生成的HashSets,但这在比较速度上没有明显的差异。

然而,这两种方法都非常慢——每次选择更改约300毫秒——特别是考虑到UI中滑块可用的日期完全基于此查询的结果,因此用户交互不得不以某种方式停止。有没有一种(非常)快速的方法可以做到这一点?

编辑:可能还不够清楚——订单对象在启动时从SQL数据中具体化,这些查询稍后在整个应用程序的辅助窗口中执行。SQL与这个问题的细节无关;这是一个LINQ to Objects问题。

检查两个枚举之间是否存在一个共同元素的最快方法

LINQ intersect将根据输入值重建一个新的HashSet,无论您做什么,即使输入已经是HashSet。它的实现会在内部对哈希集进行变异(这就是它避免产生重复值的方法),因此即使输入序列已经是HashSet,也要复制它。

您可以创建自己的Intersect方法来接受哈希集,而不是填充新的哈希集。然而,为了避免突变,你必须选择基于包的Intersect,而不是基于集的Intersect(即,序列中的重复项都会产生)。显然,在你的情况下这不是问题:

public static IEnumerable<T> IntersectAll<T>(
    this HashSet<T> set, IEnumerable<T> sequence)
{
    foreach (var item in sequence)
        if (set.Contains(item))
            yield return item;
}

现在你可以写:

SelectedProductIDs.InsersectAll(orderProductIDs).Any();

并且不需要每次都重新构建哈希集。

听起来像是将数据库中的所有值读取到内存中,然后进行查询。如果您改为使用LINQ to EF,它将把LINQ查询转换为在数据库上运行的SQL查询,这可能会更快。