2013-10-25 46 views
9

我想知道这是否可能使用lambda表达式来解决:自相交拉姆达

List<Foo> listOne = service.GetListOne(); 
List<Foo> listTwo = service.GetListTwo(); 
List<Foo> result = new List<Foo>(); 

foreach(var one in listOne) 
{ 
    foreach(var two in listTwo) 
    { 
     if((one.Id == two.Id) && one.someKey != two.someKey) 
      result.Add(one); 
    } 
} 

回答

11

当然可以!您可以使用this overload的LINQ的Intersect扩展方法,这需要一个IEqualityComparer<T>,像这样的:

public class FooComparer : IEqualityComparer<Foo> 
{ 
    public bool Equals(Foo x, Foo y) 
    { 
     return x.Id == y.Id && x.someKey != y.someKey; 
    } 

    public int GetHashCode(Foo x) 
    { 
     return x.Id.GetHashCode(); 
    } 
} 

... 

var comparer = new FooComparer(); 
List<Foo> listOne = service.GetListOne(); 
List<Foo> listTwo = service.GetListTwo(); 
List<Foo> result = listOne.Intersect(listTwo, comparer).ToList(); 
+0

不错,谢谢!如果我将第一列与第二列相交无关紧要,对吧? – Johan

+0

@Johan我相信可能会有一些性能差异,这取决于哪一组更大。当然,如果你以一种不完全对称的方式实现'IEqualityComparer',那么它就会有所作为。 –

+0

Sooo ...从最安全的角度开始吧? – Johan

2
var result = from one in listOne 
      join two in listTwo on one.Id equals two.Id 
      where one.SomeKey != two.SomeKey 
      select one; 

更新:看来,有些人觉得这是不回答这个问题,因为它理应不使用lambda表达式。当然,它只是使用友好的查询语法。

这里是完全相同的代码,只有少可读性:

var result = 
    listOne.Join(listTwo, one => one.Id, two => two.Id, (one, two) => new { one, two }) 
      .Where(p => p.one.someKey != p.two.someKey) 
      .Select(p => p.one); 
3
listOne.SelectMany(x=>listTwo.Where(y=>x.Id==y.Id && x.someKey != y.someKey)); 
+1

Johan似乎很关心表现。虽然这是他的初始代码的直接翻译,但它也具有相同的O(n x m)复杂性。这是目前所有答案中效率最低的。 –

+0

为什么不呢?使用该解决方案加入我们比他的原始代码更有效率。虽然他可以编写比Linq解决方案更高效的代码,但这可能需要很长时间,并导致代码难以读取,无法维护。 –

+0

@KrisVandermotten问题是'解决使用lambda表达式'..OP从来没有提到任何关于性能..! – Anirudha

2

你可以试试:

var result = listOne.Join(listTwo, 
    (one) => one, 
    (two) => two, 
    (one, two) => one, 
    new MyFooComparer()); 

MyFooComparer可能看起来像:

class MyFooComparer : IEqualityComparer<Foo> 
{ 
    public bool Equals(Foo x, Foo y) 
    { 
     return x.Id == y.Id && x.someKey != y.someKey; 
    } 

    public int GetHashCode(Foo obj) 
    { 
     return obj.Id.GetHashCode(); 
    } 
} 

[更新]

我很好奇IntersectJoin的表现让我做我的解决方案,并@ PSWG的之间有一个小的性能比较(listOnelistTwo各有10个项目):

var comparer = new MyFooComparer(); 
var sw = new Stopwatch(); 
sw.Start(); 
for (int i = 0; i < 100000; i++) 
{ 
    var result1 = listOne.Intersect(listTwo, comparer).ToList(); 
} 
Console.WriteLine("Intersect: {0}",sw.Elapsed); 
sw.Restart(); 
for (int i = 0; i < 100000; i++) 
{ 
    var result = listOne.Join(listTwo, 
     (one) => one, 
     (two) => two, 
     (one, two) => one, 
     comparer); 
} 
Console.WriteLine("Join:  {0}", sw.Elapsed); 

输出:

Intersect: 00:00:00.1441810 
Join:  00:00:00.0037063 
+0

.net会以某种方式调整代码..最好是通过不同的方式运行这些测试并预热一段时间..这不是基准测试的方法 – Anirudha

+0

@Anirudh,我完全同意,不是测试它的最佳方式。但即使通过颠倒顺序,结果也是一样的。 –