如何同时迭代两个 IEnumerable?
我有两个枚举: IEnumerable; list1
和 IEnumerable列表2。我想同时迭代它们,例如:
foreach((a, b) in (list1, list2))
{
// use a and b
}
如果它们不包含相同数量的元素,则应抛出异常。
最好的方法是什么?
I have two enumerables: IEnumerable<A> list1
and IEnumerable<B> list2
. I would like to iterate through them simultaneously like:
foreach((a, b) in (list1, list2))
{
// use a and b
}
If they don't contain the same number of elements, an exception should be thrown.
What is the best way to do this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
您需要类似
Zip
< /a> LINQ 运算符 - 但 .NET 4 中的版本总是在任一序列完成时截断。MoreLINQ 实现 有一个
EquiZip
方法将抛出InvalidOperationException
相反。You want something like the
Zip
LINQ operator - but the version in .NET 4 always just truncates when either sequence finishes.The MoreLINQ implementation has an
EquiZip
method which will throw anInvalidOperationException
instead.下面是此操作的一种实现,通常称为 Zip:
要使其在其中一个序列用完值时抛出异常,请更改 while 循环,如下所示:
Here's an implementation of this operation, typically called Zip:
To make it throw an exception if just one of the sequences run out of values, change the while-loop so:
简而言之,该语言没有提供干净的方法来做到这一点。枚举被设计为一次对一个枚举进行。您可以很容易地模仿 foreach 为您所做的事情:
如果它们的长度不同该怎么办取决于您。也许在 while 循环完成后找出哪一个仍然有元素并继续处理那个元素,如果它们应该具有相同的长度则抛出异常,等等。
In short, the language offers no clean way to do this. Enumeration was designed to be done over one enumerable at a time. You can mimic what foreach does for you pretty easily:
What to do if they are of different length is up to you. Perhaps find out which one still has elements after the while loop is done and keep working with that one, throw an exception if they should be the same length, etc.
在 .NET 4 中,您可以在
IEnumerable
上使用 .Zip 扩展方法,但是它不会抛出不相等的长度。不过,你总是可以测试一下。
In .NET 4, you can use the .Zip extension method on
IEnumerable<T>
It won't throw on unequal lengths, however. You can always test that, though.
使用 IEnumerable.GetEnumerator,这样您就可以在枚举中移动。请注意,这可能会产生一些非常令人讨厌的行为,您必须小心。如果你想让它工作,就用这个,如果你想要有可维护的代码,请使用两个 foreach。
如果您要在代码中多次使用此功能,您可以创建一个包装类或使用一个库(如 Jon Skeet 建议的那样)以更通用的方式处理此功能。
我建议的代码:
Go with IEnumerable.GetEnumerator, so you can move around the enumerable. Note that this might have some really nasty behavior, and you must be careful. If you want to get it working, go with this, if you want to have maintainable code, use two foreach.
You could create a wrapping class or use a library (as Jon Skeet suggests) to handle this functionality in a more generic way if you are going to use it more than once thru your code.
The code for what I suggest:
使用
Zip
函数,例如This 不会引发异常,但是......
Use the
Zip
function likeThis doesn't throw an exception, though ...
你可以做这样的事情。
C# 没有 foreach 可以按照你想要的方式执行(据我所知)。
You can do something like this.
C# has no foreach that can do it how you want (that I am aware of).
由于 C# 7.0 引入了元组,您可以创建一个返回
IEnumerable<(T1, T2)>
的通用Lockstep
函数:并像这样使用它:
如果您需要三个或更多枚举,您可以使用三个或更多参数重载
Lockstep
。Since C# 7.0 introduced tuples, you can create a generic
Lockstep
function that returns anIEnumerable<(T1, T2)>
:And use it like this:
If you need three or more enumerations, you can overload
Lockstep
with three or more parameters.