c#,用多个. where()语句过滤IEnumerable,性能提升
本文关键字:IEnumerable 过滤 性能 语句 where | 更新日期: 2023-09-27 18:03:20
我有一个IEnumerable,我通过. where表达式应用多个过滤器。我的代码看起来像这样
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();
}
我是否只迭代我的集合一次?(因为我只有一个数据库调用与LINQ到SQL)
Enumerables延迟执行,直到您遍历它们,并且在通过集合的单个迭代上应用多个过滤器。与其他linq语句结合可能会强制提前枚举,我没有测试每一个组合。这只会在非常大的数据集或低规格性能关键系统上出现问题。
下面是一个使用Visual studio c#交互的例子
> 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
>
注意,1、2和3被过滤掉了,并且没有对它们调用第二个过滤方法。4、5和6都通过第一个过滤器,因此两个过滤器都被应用。
要点:注意,在可枚举对象被读入列表之前,过滤实际上不会发生。您将能够继续添加过滤器,直到将结果枚举到列表中。
首先结果肯定是空的因为你用不同的值过滤了相同的属性,假设你纠正了这个,回答了你的问题,对于iqueryable它只会调用数据库一次,对于Enumerable对象也是一样的,因为迭代只会发生当你用foreach或调用GetEnumerator迭代对象时,在你的情况下,你没有这样做
如果您有许多过滤器,由于许多委托创建和调用以及对Where
的许多调用,开销可能会变得明显。也就是说,您可能应该运行性能测试来确定它是否真的是一个问题。
您可以重构代码以测试相同谓词中的所有过滤器:
public List<MyObject> FilteringFunction(List<MyObject> listToFilter, List<Filter> filters)
{
Func<MyObject, bool> predicate =
x =>
filters.All(f => x.Value.Contains(f.Value));
return listToFilter.Where(predicate).ToList();
}
PS:关于这个:
// A dirty way to have an enumerable instead of List
有一个更干净的方法:
var enumerableToFilter = listToFilter as IEnumerable<MyObject>;
甚至:
var enumerableToFilter = listToFilter.AsEnumerable();