Reputation: 11064
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.
Upvotes: 4
Views: 5854
Reputation: 73
I created this extension method: Notice that the second sequence can have different type, however you have to specify the key and optionally the comparer.
public static IEnumerable<TOuter> Except<TOuter, TInner, TKey>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, IEqualityComparer<TKey> comparer) {
IEnumerable<TOuter> iguales = outer.Join(
inner : inner,
outerKeySelector: tOuter => outerKeySelector(tOuter),
innerKeySelector: tInner => innerKeySelector(tInner),
resultSelector : (o, _) => o,
comparer : comparer);
return outer.Except(iguales);
}
Here's how you can use it
String name = "John";
Char[] chars = { 'h', 'n' };
var result = name.Except(
inner : chars,
outerKeySelector: c => c,
innerKeySelector: c => c); // result will contain J, o
Upvotes: 0
Reputation: 6495
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.
Upvotes: 6
Reputation: 416049
Look at the .Except()
extension method, combined with a projection:
list1 = list1.Except(list2.Select(Function(l) l.ID))
Upvotes: 7
Reputation: 1502296
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)
Upvotes: 7