遍历一个IEnumerable集合中的每个元素

8

我有三个(编辑)互斥的IEnumerable,我想要遍历它们。我想要像这样做:

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应该是微不足道的。
4个回答

20

LINQ可以实现:

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

这里需要注意的是,UnionConcat的区别在于Union会额外做一些工作来确保唯一性;所以如果您不期望出现重复项(或者说:可以接受重复项),那么使用Concat会更快。


2
呵呵...我一开始用的是Concat,然后转向了Union,但最终还是无法决定该用哪个,所以删掉了我的回答。不过我更喜欢你解释它们之间区别的方式。点赞! - Randolpho
@sdr:请注意这里存在时间/空间权衡。假设您不是有三个,而是有二十个这样的列表,每个列表都有一万个元素。您的方法(将它们全部连接成一个大列表)需要额外的20 x 10K个引用,并且需要20 x 10K个引用复制操作。另一方面,进行20个朴素的连接不需要额外的引用,但嵌套连接的复制负担基于其嵌套深度,因此将有110K次复制,而不是20K次复制。有关详细信息,请参见http://blogs.msdn.com/wesdyer/archive/2007/03/23/all-about-iterators.aspx。 - Eric Lippert
1
@Eric - 那么在假设的未来版本的C#中,有没有希望获得yield foreach结构? - kvb

3

正如其他答案中所提到的,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) { ... }

如果你发现需要遍历的列表数量实际上超过了三个,那么这种方法会更加灵活。


0

使用LINQ Union方法。

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

如果你一定要在一个循环中完成这个任务,我会选择使用LINQ。 - Scott J
没想到这一点。但是这不会很昂贵吗?因为它必须比较所有的东西。特别是因为这三个组是互斥的。 - sdr
1
请注意,这里使用 Union 操作会比 Concat 更加耗费资源,并且可能会产生与 AddRange 方法不同的结果(实质上是一个 Concat 操作)。 - Marc Gravell
如果集合没有共有元素,最好使用Marc Garvell提到的Concat。@sdr - Elisha

0

你需要在一个循环中完成这个任务吗?如果是的话,第二种方法可能是最好的选择。没有任何方法可以像第一种方式那样工作。

除非有必须在一个循环中完成的需求,否则我会使用三个循环来完成,这样更加高效。


1
我认为“更加时间高效”是一个很大的说法。还要注意到创建一个列表(包括分配、复制等)也有开销。而且,确实有一种方法能够像第一种方式一样工作。 - Marc Gravell
@Scott,如果他以相同的方式处理每辆汽车,为什么他需要多个循环呢?那只是冗余的代码。 - Anthony Pegram

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接