Reputation: 18857
If I have an IEnumerable where ClassA exposes an ID property of type long. Is it possible to use a Linq query to get all instances of ClassA with ID belonging to a second IEnumerable?
In other words, can this be done?
IEnumerable<ClassA> = original.Intersect(idsToFind....)?
where original is an IEnumerable<ClassA>
and idsToFind is IEnumerable<long>
.
Upvotes: 55
Views: 105111
Reputation: 61
I've been tripping up all morning on Intersect, and how it doesn't work anymore in core 3, due to it being client side not server side.
From a list of items pulled from a database, the user can then choose to display them in a way that requires children to attached to that original list to get more information.
What use to work was:
itemList = _context.Item
.Intersect(itemList)
.Include(i => i.Notes)
.ToList();
What seems to now work is:
itemList = _context.Item
.Where(item => itemList.Contains(item))
.Include(i => i.Notes)
.ToList();
This seems to be working as expected, without any significant performance difference, and is really no more complicated than the first.
Upvotes: 0
Reputation: 23521
Naming things is important. Here is an extension method base on the Join
operator:
private static IEnumerable<TSource> IntersectBy<TSource, TKey>(
this IEnumerable<TSource> source,
IEnumerable<TKey> keys,
Func<TSource, TKey> keySelector)
=> source.Join(keys, keySelector, id => id, (o, id) => o);
You can use it like this var result = items.IntersectBy(ids, item => item.id)
.
Upvotes: 1
Reputation: 8098
I will post an answer using Intersect
.
This is useful if you want to intersect 2 IEnumerables
of the same type.
First we will need an EqualityComparer
:
public class KeyEqualityComparer<T> : IEqualityComparer<T>
{
private readonly Func<T, object> keyExtractor;
public KeyEqualityComparer(Func<T, object> keyExtractor)
{
this.keyExtractor = keyExtractor;
}
public bool Equals(T x, T y)
{
return this.keyExtractor(x).Equals(this.keyExtractor(y));
}
public int GetHashCode(T obj)
{
return this.keyExtractor(obj).GetHashCode();
}
}
Secondly we apply the KeyEqualityComparer
to the Intersect
function:
var list3= list1.Intersect(list2, new KeyEqualityComparer<ClassToCompare>(s => s.Id));
Upvotes: 20
Reputation: 887385
Yes.
As other people have answered, you can use Where
, but it will be extremely inefficient for large sets.
If performance is a concern, you can call Join
:
var results = original.Join(idsToFind, o => o.Id, id => id, (o, id) => o);
If idsToFind
can contain duplicates, you'll need to either call Distinct()
on the IDs or on the results or replace Join
with GroupJoin
(The parameters to GroupJoin would be the same).
Upvotes: 64
Reputation: 48265
A simple way would be:
IEnumerable<ClassA> result = original.Where(a => idsToFind.contains(a.ID));
Upvotes: 6
Reputation: 39833
You can do it, but in the current form, you'd want to use the Where
extension method.
var results = original.Where(x => yourEnumerable.Contains(x.ID));
Intersect
on the other hand will find elements that are in both IEnumerable
's. If you are looking for just a list of ID's, you can do the following which takes advantage of Intersect
var ids = original.Select(x => x.ID).Intersect(yourEnumerable);
Upvotes: 12
Reputation: 96477
Use the Where method to filter the results:
var result = original.Where(o => idsToFind.Contains(o.ID));
Upvotes: 2