【问题标题】:How to get matches between collections of different types?如何在不同类型的集合之间获得匹配?
【发布时间】:2011-08-19 16:14:42
【问题描述】:

我认为这需要O(A x B) 时间来执行。

(其中 A 是 collectionA 的大小,B 是 collectionB 的大小)

我说的对吗?

IEnumerable<A> GetMatches(IEnumerable<A> collectionA, IEnumerable<B> collectionB)
{
    foreach (A a in collectionA)
        foreach (B b in collectionB)
            if (a.Value == b.Value)
                yield return a;
}

有没有更快的方法来执行这个查询? (也许使用 LINQ?)

【问题讨论】:

    标签: c# linq algorithm optimization collections


    【解决方案1】:

    不幸的是,Enumerable.Intersect 在与两种不同的类型(AB)进行比较时无法正常工作。

    这需要单独进行一些处理才能获得有效的 Intersect 调用。

    您可以分阶段进行:

    IEnumerable<A> GetMatches(IEnumerable<A> collectionA, IEnumerable<B> collectionB)
         where A : ISomeConstraintWithValueProperty
         where B : ISomeOtherConstraintWithSameValueProperty
    {
        // Get distinct values in A
        var values = new HashSet<TypeOfValue>(collectionB.Select(b => b.Value));
    
        return collectionA.Where(a => values.Contains(a.Value));
    }
    

    请注意,如果collectionB 包含重复项(但不包含collectionA),这将返回重复项,因此它的结果与您的循环代码略有不同。

    如果您想要唯一的匹配项(仅返回一个),您可以将最后一行更改为:

    return collectionA.Where(a => values.Contains(a.Value)).Distinct();
    

    【讨论】:

    • 我建议您在何时使用哪个集合,即急切地使用 collectionB,然后流式传输 collectionA - 只是因为这更适合 LINQ to Objects 的其余部分。跨度>
    • @Jon: 好点 - 还注意到我在那里的一个错误(为此,HashSet 需要是值的哈希,而不是对象本身......)你在想吗?
    • 这个解决方案的复杂性如何?
    • @asmo:好多了,因为 HashSet.Contains 是 O(1)...你仍然在枚举所有 A,但这比上面的二次方法要好得多。
    【解决方案2】:

    您可以尝试以下交集算法,如果您的数据已排序,则复杂度为 O(m+n),否则为 O(nlogn),而不会消耗额外的内存:

        private static IEnumerable<A> Intersect(A[] alist, B[] blist)
        {
            Array.Sort(alist);
            Array.Sort(blist);
    
            for (int i = 0, j = 0; i < alist.Length && j < blist.Length;)
            {
                if (alist[i].Value == blist[j].Value)
                {
                    yield return alist[i];
                    i++;
                    j++;
                }
                else
                {
                    if (alist[i].Value < blist[j].Value)
                    {
                        i++;
                    }
                    else
                    {
                        j++;
                    }
                }
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2014-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-14
      • 1970-01-01
      • 2012-12-21
      • 1970-01-01
      • 2021-01-03
      相关资源
      最近更新 更多