Reputation: 1078
I have two lists:
List<objA> list1
List<objB> list2
class objA
{
string Name;
}
class objB
{
string Name;
bool SomeProp;
}
Using C# linq/lambda I want to select all the objA objects which has their Name property equals to the name property of the second obj (list1.Name == list2.Name) and check another property of objB (list2.SomeProp == true).
Upvotes: 3
Views: 878
Reputation: 236218
I recommend to use join:
from a in list1
join b in list2 on a.Name equals b.Name
where b.SomeProp
select a
Lambda syntax:
list1.Join(listb.Where(b => b.SomeProp),
a => a.Name, b => b.Name, (a,b) => a)
NOTE: Thus you will avoid enumerating list2 collection for each item in list1 (solution with Any
)
To show difference between two solutions - lets see what they look like after translating linq to plain loops. First is
list1.Where(a => list2.Any(b => b.Name == a.Name && b.SomeProp))
It is equivalent to
foreach(var a in list1)
{
foreach(var b in list2)
{
if (a.Name == b.Name && b.SomeProp)
{
yield return a;
break;
}
}
}
As you can see - it has nested loop, and complexity is O(N*M). With join we have Lookup created for inner sequence:
Lookup<string, objB> lookup = list2.Where(b => b.SomeProp).ToLookup(b => b.Name);
foreach(var a in list1)
{
Grouping<string, objB> g = lookup.GetGrouping(a.Name);
if (g == null)
continue;
foreach(var b in g)
yield return a;
}
Difference here is searching in lookup - which is O(1) operation. Total complexity will be O(M +N)
Upvotes: 7
Reputation: 101681
This should do it:
list1.Where(a => list2.Any(b => b.Name == a.Name && b.SomeProp));
Upvotes: 4