2

I want to know how to get the elements that are not into another list of the same type.

Example

List<Person> list1;
List<Person> list2;

list1[0] = "A"
list1[1] = "B"
list1[2] = "C"
list1[3] = "D"

list2[0] = "C"
list2[1] = "D"

I want a new list with the elements A and B

I was trying to do this but it's not working.

var newList =list1.Except(list2).ToList();
2
  • What's not working about it? Commented Dec 5, 2013 at 0:13
  • 1
    Yes, this should be working if you are using the System.Linq namespace Commented Dec 5, 2013 at 0:15

2 Answers 2

2

1) Note that Person is likely not a value type, but a reference type. Therefore, Except will not compare values, but rather references. If you want to apply the "Except" logic by a property of the instances (let's say "Name"), then use something like this:

string[] valuesToExclude = list1.Select(person => person.Name).ToArray();
var newList = list2.Where(person => !valuesToExclude.Contains(person.Name)).ToList();

2) You could alternatively pass an IEqualityComparer<Person> to Except:

public class PersonComparer : IEqualityComparer<Person>
{
    public bool Equals(Person x, Person y)
    {
        return Equals(x.Name, y.Name);
    }

    public int GetHashCode(Person obj)
    {
        return obj.Name.GetHashCode();
    }
}

It's the second parameter, as in:

var newList = list2.Except(list1, new PersonComparer()).ToList();

3) Lastly, it's worth noting that if Person were a struct (value type), then your code would work as-is, assuming that all the properties matched for the instances you are excepting. For example:

public struct Person
{
    public string Name { get; set; }
}

List<Person> list1 = new List<Person> 
{ 
    new Person { Name = "A" }, 
    new Person { Name = "B" },  
};
List<Person> list2 = new List<Person> 
{
    new Person { Name = "A" }, 
};
var newList = list1.Except(list2).ToList(); 
   // "B" only
Sign up to request clarification or add additional context in comments.

Comments

2

The code you have is most likely not working because it's doing reference comparisons, meaning if A and B are Person objects and have the same values for every property A != B is true and A == B is false. Now if I had;

Person A = new Person();
Person B = A;

A == B // this is true now, that's the comparison Except is doing

So, you probably want to define a custom equality comparer. You can do that like so;

   class PersonEqualityComparer : IEqualityComparer<Person>
    {
        public bool Equals(Person lhs, Person rhs)
        {
            return lhs.Name == rhs.Name;
        }

        public int GetHashCode(Person p)
        {
            return p.Name.GetHashCode();
        }
    }

Then call Except like so;

 var diff =  list1.Except(list2, new PersonEqualityComparer());

2 Comments

@jimtollan can you expand? Do mean you think there's a problem with my code or is it just not the approach you're familiar with?
evan - it's a nice take on the comparer and probably one that would have whooshed over my head, had i sat down to think about it... very nice and a +1 for your efforts...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.