15

我正在尝试使用list.Unionin合并两个列表,LinqPad但我无法让它工作并想检查我的理解是否正确。

给定这个简单的类:

public class Test 
{
   public int Id { get; set;}
   public int field1 { get; set; }

   public bool Equals(Test other)
   {        
      return this.Id.Equals(other.Id);
   }
}

两个列表是这样填充的:

List<Test> list = new List<Test>();
list.Add( new Test { Id = 1, field1 = 1});
list.Add( new Test { Id = 1, field1 = 2});
list.Add( new Test { Id = 2, field1 = 3});
list.Add( new Test { Id = 2, field1 = 4});

List<Test> list2 = new List<Test>();
list2.Add( new Test { Id = 1, field1 = 1});
list2.Add( new Test { Id = 1, field1 = 2});
list2.Add( new Test { Id = 2, field1 = 3});
list2.Add( new Test { Id = 2, field1 = 4});

然后我尝试:var mergedList = list.Union(list2).ToList();并使用简单的foreach循环输出数据并获得此输出:

ID: 1 -------- 1
ID: 1 -------- 2
ID: 2 -------- 3
ID: 2 -------- 4
ID: 1 -------- 1
ID: 1 -------- 2
ID: 2 -------- 3
ID: 2 -------- 4

我的印象是Union应该删除重复项以返回:

ID: 1 -------- 1
ID: 1 -------- 2
ID: 2 -------- 3
ID: 2 -------- 4

我做错了什么还是我误解了?

此外,它是否应该在不显式覆盖类中的Equals方法的情况下工作Test

谢谢

4

4 回答 4

18

在您的情况下,您只需定义一些方法,LINQ 对此一无所知。就像创建方法bool HeyEquateMeWith(Test other)和期望一样,LINQ 在执行集合操作时会调用它。

您需要将您的类定义如下(覆盖 ObjectEqualsGetHashCode方法):

public class Test 
{
   public int Id { get; set;}
   public int field1 { get; set; }  

   public override bool Equals(object other) //note parameter is of type object
   {        
        Test t = other as Test;
        return (t != null) ? Id.Equals(t.Id) : false;
   }

   public override int GetHashCode()
   {
        return Id.GetHashCode();
   }
}

现在Union将调用您的重写EqualsGetHashCode方法。此外,当您覆盖方法时,您应该始终覆盖。GetHashCodeEquals

于 2013-06-07T09:24:00.800 回答
2

如果对默认比较器不满意,您可以尝试类似的方法(反过来,它利用 @IlyaIvanov 提到的 GetHashCode 方法):

// get all items that "other than in first list", so Where() and Any() are our filtering expressions
var delta = list2.Where(x2 => !list.Any(x1 => (x1.Id == x2.Id) && (x1.field1 == x2.field1)));

// now let merge two enumerables that have nothing "equal" between them
var merged = list.Union(delta).ToList();
于 2015-12-02T18:05:43.810 回答
1

您可以创建一个实现类

IEqualityComparer<Test>

这个类是否定义了 Equals 和 GetHashCode 在它之后你可以将这个比较器传递给你的 Union 方法就像这样:

public class MyComparer:IEqualityComparer<Test>{
//Equals and GetHashCode
}

var mergedList = list.Union(list2, new MyComparer()).ToList();
于 2013-06-07T09:40:19.323 回答
1

只是想把这个留给那些仍然无法得到它的人。我发现这篇文章对继承自 IEqualityComparer http://alicebobandmallory.com/articles/2012/10/18/merge-collections-without-duplicates-in-c的比较类非常有用

于 2016-05-13T18:16:52.920 回答