多次读取 IEnumerable
假设我有一些代码:
var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20);
int sum1 = items.Sum(x => x.SomeFlag == true);
例如,我需要代码后面的项目集合中的一些其他总和。
int sum2 = items.Sum(x => x.OtherFlag == false);
所以我的问题是:可以多次调用 IEnumerable
上的 Linq 方法吗?也许我应该在枚举器上调用 Reset()
方法或使用 ToList
方法从项目中创建列表?
Let's say I have some code:
var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20);
int sum1 = items.Sum(x => x.SomeFlag == true);
And for example I need some other sum from the items collection later in the code.
int sum2 = items.Sum(x => x.OtherFlag == false);
So my question: Is it OK to call Linq methods on IEnumerable
more than once? Maybe I should call Reset()
method on enumerator or make list from items using ToList
method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
嗯,这真的取决于你想做什么。您可以执行两次查询(其确切含义取决于
GetAllItems()
的作用),或者您可以复制结果到列表:一旦它进入列表,显然多次迭代该列表就不是问题了。
请注意,您无法调用
Reset
,因为您没有迭代器 - 您有IEnumerable
。无论如何,我不建议一般调用IEnumerator
- 许多实现(包括 C# 编译器从迭代器块生成的任何实现)实际上并不实现Reset
(即他们抛出异常)。Well, it really depends what you want to do. You could take the hit of executing the query twice (and the exact meaning of that will depend on what
GetAllItems()
does), or you could take the hit of copying the results to a list:Once it's in a list, obviously it's not a problem to iterate over that list multiple times.
Note that you can't call
Reset
because you don't have the iterator - you have theIEnumerable<T>
. I wouldn't recommend callingIEnumerator<T>
in general anyway - many implementations (including any generated by the C# compiler from iterator blocks) don't actually implementReset
anyway (i.e. they throw an exception).我偶尔会遇到必须多次处理可枚举的情况。如果枚举成本高昂、不可重复并且会产生大量数据(如从数据库读取的 IQueryable),则不能选择多次枚举,也不能将结果缓冲在内存中。
直到今天,我经常最终编写聚合器类,我可以将项目推送到 foreach 循环中,并最终读出结果 - 远不如 LINQ 优雅。
但是等等,我刚刚说了“推”吗?这听起来不像是……反应性的吗?所以我在今晚的散步中思考着。回到家我尝试了一下——而且很有效!
该示例片段展示了如何使用标准 LINQ 运算符(即 Rx 的运算符)在一次传递中从整数序列中获取最小和最大项:
I'm occasionally in the situation that I have to process an enumerable multiple times. If enumerating is expensive, non-repeatable and yields a lot of data (like a IQueryable that reads from a database), enumerating multiple times is not an option, neither is buffering the result in memory.
Until today I often ended up writing aggregator classes into which I could push items in a foreach loop and eventually read the results out - much less elegant than LINQ is.
But wait, did I just say "push"? Doesn't that sound like... reactive? So I was thinking during tonight's walk. Back home I tried it - and it works!
The example snippet shows how to get both the minimum and maximum items from a sequence of integers in a single pass, using standard LINQ operators (those of Rx, that is):
LINQ 使用延迟执行,因此仅当您通过其他方法请求时才会枚举“items”。每个 Sum 方法都需要 O(n) 进行迭代。根据您的项目列表有多大,您可能不想多次迭代它。
LINQ uses deferred execution, so 'items' will only enumerate when you request it to via another method. Each of your Sum methods will take O(n) to iterate through. Depending on how large your items list is, you may not want to iterate over it multiple times.