问题
In other languages (ruby, python, ...) I can use zip(list1, list2)
which works like this:
If list1 is {1,2,3,4}
and list2 is {a,b,c}
then zip(list1, list2)
would return: {(1,a), (2,b), (3,c), (d,null)}
Is such a method available in .NET's Linq extensions?
回答1:
.NET 4 gives us a Zip method but it is not available in .NET 3.5. If you are curious, Eric Lippert provides an implementation of Zip that you may find useful.
回答2:
neither implementation will fill in the missing values (or check that the lengths are the same) as the question asked.
here is an implementation that can:
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult> (this IEnumerable<TFirst> first, IEnumerable<TSecond> second, Func<TFirst, TSecond, TResult> selector, bool checkLengths = true, bool fillMissing = false) {
if (first == null) { throw new ArgumentNullException("first");}
if (second == null) { throw new ArgumentNullException("second");}
if (selector == null) { throw new ArgumentNullException("selector");}
using (IEnumerator<TFirst> e1 = first.GetEnumerator()) {
using (IEnumerator<TSecond> e2 = second.GetEnumerator()) {
while (true) {
bool more1 = e1.MoveNext();
bool more2 = e2.MoveNext();
if( ! more1 || ! more2) { //one finished
if(checkLengths && ! fillMissing && (more1 || more2)) { //checking length && not filling in missing values && ones not finished
throw new Exception("Enumerables have different lengths (" + (more1 ? "first" : "second") +" is longer)");
}
//fill in missing values with default(Tx) if asked too
if (fillMissing) {
if ( more1 ) {
while ( e1.MoveNext() ) {
yield return selector(e1.Current, default(TSecond));
}
} else {
while ( e2.MoveNext() ) {
yield return selector(default(TFirst), e2.Current);
}
}
}
yield break;
}
yield return selector(e1.Current, e2.Current);
}
}
}
}
来源:https://stackoverflow.com/questions/2811822/does-linq-net3-5-support-a-zip-method