Linq表现:Any vs. Contains

时间:2013-06-25 16:00:22

标签: c# performance linq

此问题与this one有关,但不完全相同我认为

假设:

class Foo
{
  public string Bar { get; set; }
}
...
var c1 = new List<Foo>() { ... };
var c2 = new List<Foo>() { ... };

以下2个循环给出相同的结果:

  foreach (var item in c2.Where(f => c1.Any(f1 => f1.Bar.Equals(f.Bar))))
  { ... }

  foreach (var item in c2.Where(f => c1.Select(f1 => f1.Bar).Contains(f.Bar)))
  { ... }

它们同样快吗?

the other question的区别在于,此处的额外Select语句是否会改变基础集合性质的重要性。

换句话说:这包含:

foos.Contains(foo1)

采取与此相同的“类型集合

foos.Select(f=>f.Bar).Contains(foo1.Bar)

我可能的想法可能是:“一旦我们落后于Linq的Select,一切都只是'Lists',所以Any和Contains都是O(n)。”

2 个答案:

答案 0 :(得分:13)

这两个查询正在实施相同的算法。他们将为c1中的每个项目迭代c2,比较两个对象的Bar属性,并在找到匹配后立即返回。两种情况的渐近复杂性是相同的,这意味着随着两组的大小增加,它们都会同样很好地扩展(或者同样糟糕,因为情况恰好)。在一个方法与另一个方法相关的开销中,两者之间可能存在微小的差异,但差异不会很大,并且随着集合的大小增加,它们将越来越小。没有任何真正的表现理由选择其中一个而不是另一个。

没有显示的选项比其中任何一个快得多。您可以使用Join查找c1c2中也存在的所有项目,而无需对序列进行线性搜索:

var query = from first in c1
    join second in c2
    on first.Bar equals second.Bar
    select first;

另一个选择是使用HashSet而不是List,因为这可以更容易搜索:

var set = new HashSet<string>(c1.Select(item => item.Bar));

var query = c2.Where(item => set.Contains(item.Bar));

(此解决方案非常接近Join将在内部执行的操作。)

这两种解决方案都比您提出的解决方案更快批次

答案 1 :(得分:0)

您的第一种方法将迭代并比较一次并返回结果。

第二个查询会更慢,因为它会迭代并将Bar属性提取到集合中,然后迭代并与f.Bar进行比较以创建最终结果。