Dan*_*vil 53 c# iteration ienumerable
我有两个枚举:IEnumerable<A> list1
和IEnumerable<B> list2
.我想同时迭代它们,如:
foreach((a, b) in (list1, list2))
{
// use a and b
}
Run Code Online (Sandbox Code Playgroud)
如果它们不包含相同数量的元素,则应抛出异常.
做这个的最好方式是什么?
Jon*_*eet 50
你想要Zip
LINQ运算符之类的东西- 但是.NET 4中的版本总是只在序列完成时截断.
该MoreLINQ实现有EquiZip
这将抛出一个方法InvalidOperationException
来代替.
var zipped = list1.EquiZip(list2, (a, b) => new { a, b });
foreach (var element in zipped)
{
// use element.a and element.b
}
Run Code Online (Sandbox Code Playgroud)
ang*_*son 32
这是此操作的一个实现,通常称为Zip:
using System;
using System.Collections.Generic;
namespace SO2721939
{
public sealed class ZipEntry<T1, T2>
{
public ZipEntry(int index, T1 value1, T2 value2)
{
Index = index;
Value1 = value1;
Value2 = value2;
}
public int Index { get; private set; }
public T1 Value1 { get; private set; }
public T2 Value2 { get; private set; }
}
public static class EnumerableExtensions
{
public static IEnumerable<ZipEntry<T1, T2>> Zip<T1, T2>(
this IEnumerable<T1> collection1, IEnumerable<T2> collection2)
{
if (collection1 == null)
throw new ArgumentNullException("collection1");
if (collection2 == null)
throw new ArgumentNullException("collection2");
int index = 0;
using (IEnumerator<T1> enumerator1 = collection1.GetEnumerator())
using (IEnumerator<T2> enumerator2 = collection2.GetEnumerator())
{
while (enumerator1.MoveNext() && enumerator2.MoveNext())
{
yield return new ZipEntry<T1, T2>(
index, enumerator1.Current, enumerator2.Current);
index++;
}
}
}
}
class Program
{
static void Main(string[] args)
{
int[] numbers = new[] { 1, 2, 3, 4, 5 };
string[] names = new[] { "Bob", "Alice", "Mark", "John", "Mary" };
foreach (var entry in numbers.Zip(names))
{
Console.Out.WriteLine(entry.Index + ": "
+ entry.Value1 + "-" + entry.Value2);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
如果只有其中一个序列用完了值,则使其抛出异常,更改while循环,以便:
while (true)
{
bool hasNext1 = enumerator1.MoveNext();
bool hasNext2 = enumerator2.MoveNext();
if (hasNext1 != hasNext2)
throw new InvalidOperationException("One of the collections ran " +
"out of values before the other");
if (!hasNext1)
break;
yield return new ZipEntry<T1, T2>(
index, enumerator1.Current, enumerator2.Current);
index++;
}
Run Code Online (Sandbox Code Playgroud)
Mat*_*eer 17
简而言之,该语言没有提供干净的方法来做到这一点.枚举的目的是一次完成一个可枚举.你可以很容易地模仿foreach为你做的事情:
using(IEnumerator<A> list1enum = list1.GetEnumerator())
using(IEnumerator<B> list2enum = list2.GetEnumerator())
while(list1enum.MoveNext() && list2enum.MoveNext()) {
// list1enum.Current and list2enum.Current point to each current item
}
Run Code Online (Sandbox Code Playgroud)
如果它们长度不同,该怎么办取决于你.也许在while循环完成后找出哪个仍然有元素并继续使用那个元素,如果它们应该是相同的长度,则抛出异常等.
在.NET 4中,您可以在.NET中使用.Zip扩展方法 IEnumerable<T>
IEnumerable<int> list1 = Enumerable.Range(0, 100);
IEnumerable<int> list2 = Enumerable.Range(100, 100);
foreach (var item in list1.Zip(list2, (a, b) => new { a, b }))
{
// use item.a and item.b
}
Run Code Online (Sandbox Code Playgroud)
但是,它的长度不会相等。不过,您始终可以进行测试。