tags:

views:

77

answers:

5

I have two EmailAddress generic lists, I wanted a simple way of just getting all the EmailAddress objects that are in List1 that aren't in List2.

I'm thinking a left outer join of some sort with Linq but I'm a little confused on how to set that up. I'm open to a better solution as well.

Update: I should have noted these are custom data type lists of my "EmailAddress" objects.

+8  A: 

You can use the Except linq method:

var list1 = // First list generation
var list2 = // Second list generation

var result = list1.Except(list2);
Matthew Abbott
+1  A: 

Well, I am sure that people will come in here and give you a more hip, LINQesque example, but my employer only allows us to use .NET 2.0, so...

List<EmailAddress> ret = new List<EmailAddress>( );
foreach ( EmailAddress address in List1 )
{
    if( !List2.Contains( address ) )
    {
        ret.Add( address );
    }
}

Here is an example of overriding the .Equals method that may apply to you.

class EmailAddress
{
    public string Address { get; set; }

    public override bool Equals( object o )
    {
        EmailAddress toCheck = o as EmailAddress;
        if( toCheck == null ) return false;
        // obviously this is a bit contrived, but you get the idea
        return ( this.Address == toCheck.Address );
    }

    // override GetHashCode as well when overriding Equals
}
Ed Swangren
If List2 contains the EmailAddress in List1 is still adds it with this scenario. For whatever reason the Contains() method doesn't work as expected.
Brandon
That is because you have not overriden the .Equals method, so you are checking references, not values.
Ed Swangren
I'm not sure what I'd do to implement the overridden .Equals method but that makes sense on the checking references part at least.
Brandon
You can use whatever is meaningful to your application. the == operator for mutable objects typically checks reference equality. Your .Equals method may return true if, say, the email addresses are the same, regardless of whether they are technically the same object in memory or not.
Ed Swangren
Added an example.
Ed Swangren
Awesome, that makes sense, thanks for the explanation.
Brandon
A: 

list1.Except(list2);

EDIT: Example here.

shahkalpesh
A: 
        List<String> list1 = new List<string>();
        List<String> list2 = new List<string>();
        List<String> list3 = list1.Except(list2).ToList();
decyclone
+1  A: 

Most of these answers will not work since the items in List1 and List2 may be equal in the eyes of the user, but are actually references to different instances (they are not reference equal).

Assuming Address is a string property of EmailAddress, here's a left join solution.

IEnumerable<EmailAddress> query = 
  from a1 in list1
  join a2 in list2 on a1.Address equals a2.Address into g
  from x in g.DefaultIfEmpty()
  where x == null
  select a1;
David B
They will work if you properly override the Equals method so that it is meaningful. To be honest, code like that is just overcomplicating an extremely simple operation, unless there is a good reason for not overriding .Equals (which we have no way of knowing). It is good that the OP will now know how this stuff actually works though.
Ed Swangren
Can you explain how I would have overridden the Equals method for this scenario?
Brandon
Overriding Equals is a great way to introduce bugs into your code. The guidelines state that "It is recommended that any class that overrides Equals also override System.Object.GetHashCode." Of course, mortals do not override GetHashCode correctly. Hillarity ensues. http://msdn.microsoft.com/en-us/library/ms173147(VS.80).aspx
David B
Well, it is a perfectly fine thing to do as long as you understand what you are doing. It also makes a lot of sense in a situation like this. Also, if your class is immutable, than you can go ahead and override == if you like.
Ed Swangren
And even if there is a reason why the OP can't override `Equals`/`GetHashCode` on their `EmailAddress` type, then they could still use LINQ's `Except` method and pass in a custom `IEqualityComparer<T>`: For example, `var onlyInList1 = list1.Except(list2, myCustomEmailAddressComparer);`
LukeH