tags:

views:

689

answers:

3

Is there any way to select items in a list that aren't contained in another? For example:

list1 = From t In list1 Where Not list2.Contains(t.column1)

That gives me the error:

Value of type 'Integer' cannot be converted to '<anonymous type>'

which makes sense, since list2.Contains is expecting the same type as list2. However, the list types are different. I want only to select based on column comparisons.

+4  A: 

Look at the .Except() extension method, combined with a projection:

list1 = list1.Except(list2.Select(Function(l) l.ID))
Joel Coehoorn
Except still expects a list of the same type for comparison.
hypoxide
Then use a projection to map it: list1.Except(list2.Select(...) )
Joel Coehoorn
Is there a way to do this with multiple columns?
hypoxide
I'm not sure how this answer satisfies the original requirement that it's t.column1 which specifies the part of the list1 element to be excluded.
Jon Skeet
+5  A: 

Well what does list2 actually contain? If you can express your query precisely, we can probably express it in LINQ. Without knowing what list1, list2 and column1 are it's hard to help.

What I would say is that List<T>.Contains is going to be O(n) for each item you check. If list2 is potentially non-small, you may well want to create a HashSet<T> - then each Contains call will be a lot faster.

But then again, when we know more about the situation we may well suggest a completely different solution. Please make the question as concrete as possible to get the best answer.

EDIT: If tvanfosson's solution works for you and if you're using LINQ to Objects, you've got a potential performance pit there. It would be better (IMO) to do the projection on list2 once and build a set:

Dim invalid = New HashSet(Of Integer)(list2.Select(Function(x) x.Id))
list1 = From t in list1 Where Not invalid.Contains(t.column1)
Jon Skeet
As usual, Jon Skeet for the linq win ;)
Joel Coehoorn
Apparently not ;)
Jon Skeet
+2  A: 

Have you tried something like this?

list1 = From t In list1 Where Not list2.Any(l => t.column1 = l.column1 AndAlso t.column2 = l.column2)

I am unsure how efficient it would be, but I think it should work for you.

Ryan Versaw
I love how elegant that is and I think it's almost there. But I'm getting this exception: "Unable to cast object of type 'WhereListIterator`1[ToolObject]' to type 'System.Collections.Generic.List`1[ToolObject]'."
hypoxide
Throw a .ToList() onto the end? (with parenthesis around the entire statement)
Ryan Versaw
That did it. Thanks!
hypoxide