【问题标题】:Foreach over a collection of IEnumerables遍历 IEnumerables 的集合
【发布时间】:2011-01-30 12:54:40
【问题描述】:

我有 3 个(编辑)互斥 IEnumerables 我想迭代。我想做这样的事情:

IEnumerable<Car> redCars = GetRedCars();
IEnumerable<Car> greenCars = GetGreenCars();
IEnumerable<Car> blueCars = GetBlueCars();

foreach(Car c in (redCars + greenCars + blueCars)) {
    c.DoSomething();
}

...

我能想到的最好办法是:

...
List<Car> allCars = new List();
allCars.AddRange(redCars);
allCars.AddRange(greenCars);
allCars.AddRange(blueCars);
foreach(car in allCars) {
    ...
}
...

有没有更简洁的方法来做到这一点?似乎结合 IEnumberables 应该是微不足道的。

【问题讨论】:

    标签: c# foreach ienumerable


    【解决方案1】:

    使用 LINQ:

    foreach(car in redCars.Concat(greenCars).Concat(blueCars)) {
        //...
    }
    

    关于信息,UnionConcat 之间的区别在于Union 会做额外的工作来保证唯一性;因此,如果您不期望重复(或者:不介意它们),那么Concat 会更快。

    【讨论】:

    • 嘿...我从 Concat 开始,然后去了 Union,然后决定我无法决定使用哪个,所以我删除了我的答案。无论如何,我喜欢你更好地解释差异。 +1
    • 正是我想要的。谢谢!
    • @sdr:请注意,这里需要权衡时间/空间。假设您有不是三个而是二十个这样的列表,每个列表都有一万个元素。您的方法(将它们全部连接到一个大列表中)占用大约 20 x 10K 额外引用并需要 20 x 10K 引用复制操作。另一方面,执行 20 个简单的 concats 占用了 0 个额外的引用,但是嵌套的 concats 根据它们的嵌套深度有复制负担,因此将有 10 x 11 x 10K = 110K 副本,而不是 20K 副本。详情请见blogs.msdn.com/wesdyer/archive/2007/03/23/…
    • @Eric - 所以有希望在假设的 C# 未来版本中获得 yield foreach 构造吗?
    【解决方案2】:

    正如其他答案中所述,Union 做了额外的工作来消除重复,Concat 只是连接序列。但是,正如我在上面的评论中指出的那样,深度嵌套的 concat 存在性能成本。您也可以考虑使用 SelectMany 来展平一堆迭代器:

    var carLists = new[]{GetRedCars(), GetGreenCars(), GetBlueCars()};
    var allCars = from carList in carLists
                  from car in carList 
                  select car;
    foreach(var c in allCars) { ... }
    

    如果您发现实际上要迭代的列表不止三个,您可能会发现它更加灵活。

    【讨论】:

      【解决方案3】:

      使用 LINQ 联合方法。

      foreach(Car c in redCars.Union(greenCars).Union(blueCars))
      {
          c.DoSomething();
      }
      

      【讨论】:

      • 如果您绝对需要在一个循环中执行此操作,我会使用 LINQ。
      • 没想到。但这会不会太贵,因为它必须将它们全部比较?尤其是因为这三个群体是相互排斥的。
      • 对于信息,Union 将比Concat 更昂贵,并且很可能产生与AddRange 方法不同的结果(本质上是Concat)。跨度>
      • @sdr,如果集合不共享元素,最好使用 Concat,就像 Marc Garvell 提到的那样。
      【解决方案4】:

      您是否有理由需要在一个循环中执行此操作?如果是这样,第二种方法可能是最好的。没有什么能像第一种方式那样有效。

      除非有压倒一切的需要在一个循环中完成,否则我会在三个循环中完成,这样会更省时。

      【讨论】:

      • 我认为“更省时”是一个很大的主张。另请注意,创建列表(包括分配、复制等)也有开销。并且有很多可以像第一种方式一样工作。
      • @Scott,如果他以相同的方式处理每辆车,为什么他想要多个循环?这只是多余的代码。
      猜你喜欢
      • 2011-02-12
      • 2014-04-11
      • 1970-01-01
      • 2020-06-23
      • 2018-02-19
      • 1970-01-01
      • 1970-01-01
      • 2015-04-04
      相关资源
      最近更新 更多