Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am trying to merge two lists using list.Union in LinqPad but I can't get it to work and wanted to check my understanding is correct.

Given this simple class:

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

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

And two lists populated like this:

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});

I then try: var mergedList = list.Union(list2).ToList(); and output the data using a simple foreach loop and get this output:

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

I was under the impression that Union should remove the duplicates to return:

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

Am I doing something wrong or have I misunderstood?

Also, should it work without explicitly overriding the Equals method in the Test class?

Thanks

share|improve this question
1  
You should read this documentation page. –  Jon Jun 7 '13 at 9:20
    
@Jon. I will. Thank you. –  davy Jun 7 '13 at 9:45
add comment

2 Answers

up vote 7 down vote accepted

In your case you simply define some method, that LINQ knows nothing about. It's like creating method bool HeyEquateMeWith(Test other) and expect, that LINQ will call it when doing set operations.

You need to define your class as following (override Object's Equals and GetHashCode methods):

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();
   }
}

Now Union will call your overridden Equals and GetHashCode methods. Also you should ALWAYS override GetHashCode when you override Equals method.

share|improve this answer
    
Thanks. Yeah, I thought I could leave the GetHashCOde for an example but it is required. How does the default comparer work for Union or do I always need to override Equals and GethashCode? –  davy Jun 7 '13 at 9:44
1  
@davy default comparer will look at object identity (same functionality as == operator). If you change your Test class to struct, the default equality will have value semantics (compare contents of two structs including Id and field1) –  Ilya Ivanov Jun 7 '13 at 9:47
    
I see. Thank you so much for your help. –  davy Jun 7 '13 at 11:11
add comment

You can create a class implementing

IEqualityComparer<Test>

Is this class define Equals and GetHashCode After it you can pass this comparer to you Union method Just like that:

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

var mergedList = list.Union(list2, new MyComparer()).ToList();
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.