Anarion Anarion - 3 months ago 15
C# Question

C#, filtering IEnumerable with multiple .Where() statements, performance hits

I have an IEnumerable, and I'm applying multiple filters to it via .Where expression. My code looks something like this

public List<MyObject> FilteringFunction(List<MyObject> listToFilter, List<Filter> filters)
{
// A dirty way to have an enumerable instead of List
var enumerableToFilter = listToFilter.Where(x => true);

foeach(var filter in filters)
{
enumerableToFilter = enumerableToFilter.Where(x => x.Value.Contains(filter.Value));
}

return enumerableToFilter.ToList();

}


Am I going to iterate through my collection only once? (As I would have only one database call with LINQ to SQL)

Answer

Enumerables defer execution until you iterate over them, and multiple filters are applied on a single iteration through the collection. Combining with other linq statements may force early enumeration, I haven't tested every combination. This would only be a problem with very large data sets or on low spec performance critical systems.

Here is an example using Visual Studios c# interactive

> class Item
. {
.     private int _number;
.     public int Number
.     {
.         get { Console.WriteLine($"Got number {_number}"); return _number; }
.         set { _number = value; }
.     }
. }
> 
> IEnumerable<Item> items = new List<Item>() { 
.     new Item { Number = 1 },
.     new Item { Number = 2 },
.     new Item { Number = 3 },
.     new Item { Number = 4 },
.     new Item { Number = 5 },
.     new Item { Number = 6 }
. };
> 
> var filteredItems = items.Where(item => item.Number > 3).Where(item => item.Number % 2 == 0);
> 
> var listedItems = filteredItems.ToList();
Got number 1
Got number 2
Got number 3
Got number 4
Got number 4
Got number 5
Got number 5
Got number 6
Got number 6
> 

Note that 1, 2, and 3 are filtered out and the second filter method is not called on them. 4, 5, and 6 all pass the first filter so both filters are applied.

Key Point: Note that the filtering doesn't actually happen until the enumerable is read to a list. You will be able to continue appending filters until you enumerate the result to a list.