tags:

views:

171

answers:

3

I've 2 list collections in my C# app..A and B.

Both the collections have customer object which has Id and Name attributes.Typically, A has more items than B.

Using Linq,I want to return only those customers whose Id is in A but not in B.

How do I do this?

+5  A: 

There are multiple approaches to take. The cleanest approach is to use the Except extension method if you have overriden Equals and GetHashCode. If you have not, there are other options.

// have you overriden Equals/GetHashCode?
IEnumerable<Customer> resultsA = listA.Except(listB);

// no override of Equals/GetHashCode? Can you provide an IEqualityComparer<Customer>?
IEnumerable<Customer> resultsB = listA.Except(listB, new CustomerComparer()); // Comparer shown below

// no override of Equals/GetHashCode + no IEqualityComparer<Customer> implementation?
IEnumerable<Customer> resultsC = listA.Where(a => !listB.Any(b => b.Id == a.Id));

// are the lists particularly large? perhaps try a hashset approach 
HashSet<int> customerIds = new HashSet<int>(listB.Select(b => b.Id).Distinct());
IEnumerable<Customer> resultsD = listA.Where(a => !customerIds.Contains(a.Id));

...

class CustomerComparer : IEqualityComparer<Customer>
{
    public bool Equals(Customer x, Customer y)
    {
        return x.Id.Equals(y.Id);
    }

    public int GetHashCode(Customer obj)
    {
        return obj.Id.GetHashCode();
    }
}
Anthony Pegram
Thanks for ur comments...From this line:listA.Where(a => !listB.Any(b => b.Id == a.Id));, how do I get a third list "C" which has those customer objects from A not present in B?
Jimmy
@Jimmy, `List<Customer> listC = listA.Where(a => !listB.Any(b => b.Id == a.Id)).ToList();`
Anthony Pegram
Thanks Anthony Pegram!This works great for me!I used:listA.Where(a => !listB.Any(b => b.Id == a.Id)); approach.
Jimmy
+6  A: 

If you override Equals for your customer object, then just use

A.Except(B);
Larsenal
+2  A: 

Expanding on Except, providing your own equality so you don't need to change your Equals behavior. I got this from here:

http://www.codeproject.com/KB/dotnet/LINQ.aspx#distinct

List<Customer> customersA = new List<Customer> { new Customer { Id = 1, Name = "A" }, new Customer { Id = 2, Name = "B" } };
List<Customer> customersB = new List<Customer> { new Customer { Id = 1, Name = "A" }, new Customer { Id = 3, Name = "C" } };

var c = (from custA in customersA
        select custA.Id).Distinct()
             .Except((from custB in customersB
            select custB.Id).Distinct());
Jim Leonardo
In thise case, `var c` would be `IEnumerable<int>`, representing a sequence of the unique, unmatched Ids from `customersA`. To get the `Customer` objects, this result would need to be used again to extract objects from `customersA`.
Anthony Pegram