Using LINQ, how to select conditionally some items but when no conditions select all?
34,523
Solution 1
If these collections are going to be sizable, then I recommend using a join. It would look something like this:
var result =
myFilters.Any() ?
from item in myCollection
join filter in myFilters
on item.Name equals filter into gj
where gj.Any()
select item
: myCollection;
Opportunities for using joins are easily overlooked. This join approach will outperform the contains approach when the lists are remotely large. If they're small and performance is acceptable, then use whichever seems the clearest.
Solution 2
var result = myCollection
.Where(i => (!myFilters.Any() || myFilters.Contains(i.Name)));
Solution 3
The best you're going to be able to do is project the filters into SomeClass. Something like:
var results = myCollection.Any() ?
myCollection.Where(item => myFilters.Contains(item.Name)) :
myFilters.Select(f => new SomeClass (f));
Author by
Stécy
Updated on July 09, 2022Comments
-
Stécy almost 2 years
I want to select elements from myCollection using myFilters for filtering:
var myFilters = new List<string> {"111", "222"}; var myCollection = new List<SomeClass> { new SomeClass ("111"), new SomeClass ("999") }; from filter in myFilters from item in myCollection where item.Name == filter select item
would return the "111" item.
However, if myFilters is empty I want to return all the items from myCollection.
var myFilters = new List<string> (); var myCollection = new List<SomeClass> { new SomeClass ("111"), new SomeClass ("999") }; // Here's where I'm lost... from filter in myFilters from item in myCollection where item.Name == filter select item
would return all items ("111" and "999").
-
Servy over 11 yearsRather than
Count() == 0
you can useAny()
. It will not only perform better (it only needs to get the first item to know if there are any vs. needing to fetch every item to get the count) but it also semantically means exactly what you're trying to do. -
horgh over 11 years@Servy Actually I've got
Any
variant in my answer. Anyway, thanks for clarification. -
devgeezer over 11 yearsNote that this is not a subset of filtered instances from
myCollection
but a projection of newSomeClass
instances created from the matchingmyFilters
values. -
TrueWill over 11 yearsIt doesn't work (in LINQPad 4) when myFilters is empty. The OP wrote "if the second collection is empty" but meant the filters collection. If you have no filters you should get the entire collection; instead (with this query) you get an empty collection.
-
devgeezer over 11 yearsLifting the
Any()
out of the where predicate is a good move performance-wise. A nice thing about leaving theAny()
in the predicate is if the query is held onto and either themyFilters
ormyCollection
lists are altered (e.g., cleared, items added, items removed), then subsequent iteration will provide the updated result.