此问题与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)。”
答案 0 :(得分:13)
这两个查询正在实施相同的算法。他们将为c1
中的每个项目迭代c2
,比较两个对象的Bar
属性,并在找到匹配后立即返回。两种情况的渐近复杂性是相同的,这意味着随着两组的大小增加,它们都会同样很好地扩展(或者同样糟糕,因为情况恰好)。在一个方法与另一个方法相关的开销中,两者之间可能存在微小的差异,但差异不会很大,并且随着集合的大小增加,它们将越来越小。没有任何真正的表现理由选择其中一个而不是另一个。
您没有显示的选项比其中任何一个快得多。您可以使用Join
查找c1
中c2
中也存在的所有项目,而无需对序列进行线性搜索:
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
进行比较以创建最终结果。