【问题标题】:Reading an IEnumerable multiple times多次读取 IEnumerable
【发布时间】:2011-09-30 15:13:07
【问题描述】:

假设我有一些代码:

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 方法从项目中列出?

【问题讨论】:

    标签: c# linq ienumerable


    【解决方案1】:

    嗯,这真的取决于你想做什么。您可以执行两次查询(其确切含义将取决于 GetAllItems() 的作用),您可以将结果复制到列表中: p>

    var items = ItemsGetter.GetAllItems().Where(x => x.SomeProperty > 20).ToList();
    

    一旦它在一个列表中,显然多次迭代该列表不是问题。

    请注意,您不能调用 Reset,因为您没有迭代器 - 您有 IEnumerable<T>。我一般不建议调用IEnumerator<T>——许多实现(包括C#编译器从迭代器块生成的任何实现)实际上并没有实现Reset(即它们抛出异常)。

    【讨论】:

      【解决方案2】:

      我偶尔会遇到必须多次处理可枚举的情况。如果枚举成本高昂、不可重复并且产生大量数据(例如从数据库读取的 IQueryable),则不能选择多次枚举,也不能将结果缓冲到内存中。

      直到今天,我经常最终编写聚合器类,我可以在 foreach 循环中将项目推送到其中并最终读取结果 - 远不如 LINQ 优雅。

      但是等等,我刚才说的是“推”吗?这听起来不像……反应?所以我在今晚散步的时候在想。回家后我试了一下,效果很好!

      示例 sn-p 展示了如何使用标准 LINQ 运算符(即 Rx 的运算符)在一次传递中从整数序列中获取最小值和最大值:

      public static MinMax GetMinMax(IEnumerable<int> source)
      {
          // convert source to an observable that does not enumerate (yet) when subscribed to
          var connectable = source.ToObservable(Scheduler.Immediate).Publish();
      
          // set up multiple consumers
          var minimum = connectable.Min();
          var maximum = connectable.Max();
      
          // combine into final result
          var final = minimum.CombineLatest(maximum, (min, max) => new MinMax { Min = min, Max = max });
      
          // make final subscribe to consumers, which in turn subscribe to the connectable observable
          var resultAsync = final.GetAwaiter();
      
          // now that everybody is listening, enumerate!
          connectable.Connect();
      
          // result available now
          return resultAsync.GetResult();
      }
      

      【讨论】:

      【解决方案3】:

      LINQ 使用延迟执行,因此“items”只会在您通过其他方法请求时枚举。您的每个 Sum 方法都将花费 O(n) 进行迭代。根据您的项目列表的大小,您可能不希望对其进行多次迭代。

      【讨论】:

      • 嗯,“OK”是什么意思有点不清楚。您可以根据需要多次迭代列表。我在回答中提到了这一点的后果。迭代它们怎么行?如果您认为是这样,请发布您自己的答案(尽管已经有一个接受的答案)。
      • 一个 IEnumerable 是一个接口。什么说你不能多次遍历它?煨一下。
      • @JimBalter 您可以多次迭代 IEnumerables。例如,取 var x = someList.AsEnumerable(),可以执行 foreach (var y in x) { do stuff; } 不止一次。 (注意:我刚刚注意到这是几年前的,所以你现在可能知道了)
      猜你喜欢
      • 1970-01-01
      • 2020-02-05
      • 1970-01-01
      • 2016-02-24
      • 1970-01-01
      • 1970-01-01
      • 2012-07-15
      • 2013-10-26
      • 2011-05-25
      相关资源
      最近更新 更多