Language support for Zip-like simultaneous enumeration #2197
-
I propose we support (what I hope is) a very simple addition to Syntax: foreach(var a in collectionA; var b in collectionB)
{
// This block will execute only while both `a` and `b` continue to yield values
// Code goes here
} This would lower to: var $enumeratorA = collectionA.GetEnumerator();
var $enumeratorB = collectionB.GetEnumerator();
while($enumeratorA.MoveNext() && $enumeratorB.MoveNext())
{
var a =$ enumeratorA.Current;
var b = $enumeratorB.Current;
// Code goes here
} I find myself writing code like this a lot: foreach(var (a, b) in collectionA.Zip(collectionB, (x, y) => (x, y)))
{
} This would also (indirectly) provide a feature that is very oft-requested: looping over a collection with an automatic counter variable. If we combine this with ranges then I think we'll be able to write: foreach(var x in col; var i in 0..)
{
} |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 3 replies
-
I think it'd be better to ask the corefx team to add a default value tuple selector or to write that extension method on your own. I think: foreach (var (a, b) in collectionA.Zip(collectionB))
{
} is very readable. So you don't need any language support. |
Beta Was this translation helpful? Give feedback.
-
Here's the implementation I've been using: /// <exception cref="ArgumentNullException"><paramref name="first"/> or <paramref name="second"/> is <see langword="null"/></exception>
public static IEnumerable<(TFirst first, TSecond second)> Zip<TFirst, TSecond>(this IEnumerable<TFirst> first, IEnumerable<TSecond> second)
=> (first ?? throw new ArgumentNullException(nameof(first))).Zip(second ?? throw new ArgumentNullException(nameof(second)), (i1, i2) => (i1, i2)); The language feature would be nice, tho. |
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
Using extension GetEnumerator from C# 9.0, you can do this: foreach(var (a, b) in (collectionA, collectionB))
{
// This block will execute only while both `a` and `b` continue to yield values
// Code goes here
}
public static IEnumerator<(T1, T2)> GetEnumerator<T1, T2>(this (IEnumerable<T1> a, IEnumerable<T2> b) pair) => pair.a.Zip(pair.b, (a, b) => (a, b)).GetEnumerator(); |
Beta Was this translation helpful? Give feedback.
Using extension GetEnumerator from C# 9.0, you can do this: