Stécy
Stécy

Reputation: 12367

Using LINQ, how to select conditionally some items but when no conditions select all?

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").

Upvotes: 6

Views: 40479

Answers (5)

cuongle
cuongle

Reputation: 75326

var result = myCollection
                   .Where(i => (!myFilters.Any() || myFilters.Contains(i.Name)));

Upvotes: 5

horgh
horgh

Reputation: 18563

Try this:

var result = myCollection.Where(s => !myFilters.Any() ||
                                     myFilters.Contains(s.Name));
//EDIT: commented these lines..based on comment by @Servy
//var result = myCollection.Where(s => myFilters.Count == 0 ||
//                                     myFilters.Contains(s.Name));

Maybe it would be better to count filter collection only once:

bool isFilterEmpty = !myFilters.Any(); 
//bool isFilterEmpty = myFilters.Count == 0;    //...or like this
var result = myCollection.Where(s => isFilterEmpty || 
                                     myFilters.Contains(s.Name));

EDIT

I'd even say that the answer by @itsme86 is correct, but, I guess, he has confused your collections. So his answer should look somehow like this:

var results = myFilters.Any()
                 ? myCollection.Where(item => myFilters.Contains(item.Name))
                 : myCollection;

Upvotes: 0

armen.shimoon
armen.shimoon

Reputation: 6401

How about this?

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 || !myFilters.Any()
select item

Selecting from two collections performs a join based on your where clause. The join condition above says join on item.Name equal to filter OR select it if there are no filters available.

Upvotes: 0

devgeezer
devgeezer

Reputation: 4189

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.

Upvotes: 8

itsme86
itsme86

Reputation: 19526

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));

Upvotes: 2

Related Questions