2008-09-19 5 views
12

In Python gibt es eine wirklich nette Funktion zip genannt ist, die verwendet werden können, durch zwei Listen gleichzeitig iterieren:Gibt es in .Net eine zip-ähnliche Methode?

list1 = [1, 2, 3] 
list2 = ["a", "b", "c"] 
for v1, v2 in zip(list1, list2): 
    print v1 + " " + v2 

Der obige Code erzeugen sollte die folgenden:

1 a 
2 b 
3 c

Ich frage mich, ob es eine Methode wie diese in .Net gibt? Ich denke darüber nach, es selbst zu schreiben, aber es gibt keinen Sinn, wenn es schon verfügbar ist.

+0

Könnte jemand erklären, wie dies von nur "für" Schleife verschieden ist wie: for (var i; ;) {var x = arr1 [i]; var y = arr2 [i]; } Ich nehme an, dass es einen komplexen Unterschied gibt, den ich hier nicht sehe. –

+2

Allen, gibt es nicht, zumindest nicht für Arrays. Zip funktioniert jedoch mit allem, was Sie durchlaufen können, nicht nur z. Arrays. –

+0

Allen: zip() ist ein Ausdruck. Ihre Alternative ist ein Codeblock. – recursive

Antwort

25

Update: Es ist eingebaut in C# 4 als System.Linq.Enumerable.Zip Method

Hier eine Version C# 3:

IEnumerable<TResult> Zip<TResult,T1,T2> 
    (IEnumerable<T1> a, 
    IEnumerable<T2> b, 
    Func<T1,T2,TResult> combine) 
{ 
    using (var f = a.GetEnumerator()) 
    using (var s = b.GetEnumerator()) 
    { 
     while (f.MoveNext() && s.MoveNext()) 
      yield return combine(f.Current, s.Current); 
    } 
} 

Dropped die C# 2-Version, wie es sein Alter zeigte.

+0

Wäre schön, auch das Paar <,> zu definieren oder einen zusätzlichen Parameter zu übernehmen, der als Ergebnisselektor dient. –

+0

Wow, ich bin erstaunt. Während ich meine Antwort eintippte biete ich fast 100% ähnliche Lösung an :) – aku

+0

Dies ist eine der idealen Situationen für die Verwendung des "var" -Schlüsselworts (wenn Sie auf 3.5 waren): foreach (var Paar in Zip (Ints, Strings)) Sie verlieren das Rauschen des Paares Erklärung, die für mich nicht benötigt wird. –

5

Nein, es gibt keine solche Funktion in .NET. Du hast deine eigenen rausgebracht. Beachten Sie, dass C# keine Tupel unterstützt, daher fehlt auch pythonähnlicher Syntaxzucker.

Sie können so etwas wie folgt verwenden:

class Pair<T1, T2> 
{ 
    public T1 First { get; set;} 
    public T2 Second { get; set;} 
} 

static IEnumerable<Pair<T1, T2>> Zip<T1, T2>(IEnumerable<T1> first, IEnumerable<T2> second) 
{ 
    if (first.Count() != second.Count()) 
     throw new ArgumentException("Blah blah"); 

    using (IEnumerator<T1> e1 = first.GetEnumerator()) 
    using (IEnumerator<T2> e2 = second.GetEnumerator()) 
    { 
     while (e1.MoveNext() && e2.MoveNext()) 
     { 
      yield return new Pair<T1, T2>() {First = e1.Current, Second = e2.Current}; 
     } 
    } 
} 

... 

var ints = new int[] {1, 2, 3}; 
var strings = new string[] {"A", "B", "C"}; 

foreach (var pair in Zip(ints, strings)) 
{ 
    Console.WriteLine(pair.First + ":" + pair.Second); 
} 
+0

+1 für die Verwendung von using-Blöcken –

8

Soweit ich weiß gibt es nicht. Ich schrieb einen für mich (wie auch einige andere nützliche Erweiterungen und sie in einem Projekt NExtension auf Codeplex genannt gestellt.

Anscheinend ist die Parallel-Erweiterungen für .NET, um eine Zip-Funktion.

Hier ist eine vereinfachte Version von NExtension (aber überprüfen sie es bitte für weitere nützliche Erweiterung Methoden aus):

public static IEnumerable<TResult> Zip<T1, T2, TResult>(this IEnumerable<T1> source1, IEnumerable<T2> source2, Func<T1, T2, TResult> combine) 
{ 
    using (IEnumerator<T1> data1 = source1.GetEnumerator()) 
    using (IEnumerator<T2> data2 = source2.GetEnumerator()) 
     while (data1.MoveNext() && data2.MoveNext()) 
     { 
      yield return combine(data1.Current, data2.Current); 
     } 
} 

Verbrauch:

int[] list1 = new int[] {1, 2, 3}; 
string[] list2 = new string[] {"a", "b", "c"}; 

foreach (var result in list1.Zip(list2, (i, s) => i.ToString() + " " + s)) 
    Console.WriteLine(result); 
+0

Schöne Antwort. Sie sollten ein Beispiel für die Verwendung der Funktion in C# 3.0 – Coincoin

+0

gleichen Kommentar hier als die akzeptierte Antwort hinzufügen, IEnumerator IDisposable ist, sollten Sie einige using-Blöcke hinzufügen. –

2

es gibt auch ein in F #:

let Reißverschluss = Seq.zip firstEnumeration secondEnumation

Verwandte Themen