Come iterare più elegantemente attraverso le collezioni parallele in C #?
-
11-09-2019 - |
Domanda
var a = new Collection<string> {"a", "b", "c"};
var b = new Collection<int> { 1, 2, 3 };
Qual è il modo più elegante per scorrere sia producendo una serie di risultati "A1", "B2", "C3"?
Soluzione
Questo è noto come "lampo" o "zip unire" due sequenze. Eric Lippert descrive questo algoritmo molto e fornisce un'implementazione.
Altri suggerimenti
Il potente Bart de Smet parla di funzioni zip qui:
La sua soluzione più elegante si avvale di un sovraccarico di selezione che prende un parametro di 2 Funz delegato come parametro.
a.Select((t,i)=>new{t,i});
In questo esempio, i rappresenta semplicemente l'indice dell'elemento in lavorazione. Così si può creare 2 nuovi enumerables di questi oggetti anonimi e unirsi a loro su i.
Performance-saggio, mi piacerebbe andare con un ciclo di cedimento più evidente.
Per completare i grandi messaggi di Eric e Bart, ecco un'implementazione utilizzando System.Linq 3,5 operatori:
public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult> (
this IEnumerable<TFirst> first,
IEnumerable<TSecond> second,
Func<TFirst, TSecond, TResult> resultSelector)
{
return from aa in a.Select((x, i) => new { x, i })
join bb in b.Select((y, j) => new { y, j })
on aa.i equals bb.j
select resultSelector(aa.x, bb.y);
}
È possibile creare un blocco iteratore per gestire questa situazione con eleganza:
public static class Ext
{
public static IEnumerable<string> ConcatEach(this IEnumerable a,
IEnumerable b)
{
var aItor = a.GetEnumerator();
var bItor = b.GetEnumerator();
while (aItor.MoveNext() && bItor.MoveNext())
yield return aItor.Current.ToString() + bItor.Current;
}
}
Lo chiamano elegantemente =) come:
var a = new Collection<string> {"a", "b", "c"};
var b = new Collection<int> {1, 2, 3};
foreach(var joined in a.ConcatEach(b))
{
Console.WriteLine(joined);
}