Der Zip-Operator führt die entsprechenden Elemente zweier Sequenzen mithilfe einer angegebenen Auswahlfunktion zusammen.
var letters=newstring[]{"A","B","C","D","E"};var numbers=newint[]{1,2,3};var q = letters.Zip(numbers,(l, n)=> l + n.ToString());foreach(var s in q)Console.WriteLine(s);
Ich mag diese Antwort, weil sie zeigt, was passiert, wenn die Anzahl der Elemente nicht übereinstimmt, ähnlich wie in der MSDN-Dokumentation
DLeh
2
Was ist, wenn Zip fortgesetzt werden soll, wenn in einer Liste keine Elemente mehr vorhanden sind? In diesem Fall sollte das kürzere Listenelement den Standardwert annehmen. Die Ausgabe erfolgt in diesem Fall A1, B2, C3, D0, E0.
Liang
2
@liang Zwei Möglichkeiten: A) Schreiben Sie Ihre eigene ZipAlternative. B) Schreiben auf ein Verfahren yield returnjedes Element der kürzeren Liste, und dann weiter yield returning auf defaultunbestimmte Zeit danach. (Option B erfordert, dass Sie im Voraus wissen, welche Liste kürzer ist.)
jpaugh
105
Zipdient zum Kombinieren von zwei Sequenzen zu einer. Zum Beispiel, wenn Sie die Sequenzen haben
1,2,3
und
10,20,30
und Sie möchten die Sequenz erhalten, die das Ergebnis der Multiplikation von Elementen an derselben Position in jeder Sequenz ist
10,40,90
du könntest sagen
var left =new[]{1,2,3};var right =new[]{10,20,30};var products = left.Zip(right,(m, n)=> m * n);
Es wird als "Reißverschluss" bezeichnet, da Sie sich eine Sequenz als die linke Seite eines Reißverschlusses und die andere Sequenz als die rechte Seite des Reißverschlusses vorstellen Elemente der Sequenz) angemessen.
Liebte das Beispiel des Reißverschlusses. Es war so natürlich. Mein erster Eindruck war, ob es etwas mit Geschwindigkeit oder so etwas zu tun hat, als ob Sie mit Ihrem Auto durch eine Straße fahren.
RBT
23
Es durchläuft zwei Sequenzen und kombiniert ihre Elemente nacheinander zu einer einzigen neuen Sequenz. Sie nehmen also ein Element der Sequenz A, transformieren es mit dem entsprechenden Element aus Sequenz B und das Ergebnis bildet ein Element der Sequenz C.
Eine Möglichkeit, darüber nachzudenken, besteht darin, dass es ähnlich ist Select, außer dass Elemente aus einer einzelnen Sammlung transformiert werden und zwei Sammlungen gleichzeitig bearbeitet werden.
int[] numbers ={1,2,3,4};string[] words ={"one","two","three"};var numbersAndWords = numbers.Zip(words,(first, second)=> first +" "+ second);foreach(var item in numbersAndWords)Console.WriteLine(item);// This code produces the following output:// 1 one// 2 two// 3 three
Wenn Sie dies in imperativem Code tun würden, würden Sie wahrscheinlich Folgendes tun:
for(int i =0; i < numbers.Length&& i < words.Length; i++){
numbersAndWords.Add(numbers[i]+" "+ words[i]);}
Oder wenn LINQ nicht Zipdrin wäre, könnten Sie dies tun:
var numbersAndWords = numbers.Select((num, i)=> num +" "+ words[i]);
Dies ist nützlich, wenn Sie Daten in einfachen, Array-ähnlichen Listen mit jeweils gleicher Länge und Reihenfolge verteilen und jeweils eine andere Eigenschaft derselben Objektgruppe beschreiben. Ziphilft Ihnen, diese Daten zu einer kohärenteren Struktur zusammenzufügen.
Wenn Sie also ein Array von Statusnamen und ein anderes Array ihrer Abkürzungen haben, können Sie diese Statewie folgt zu einer Klasse zusammenfassen:
IEnumerable<State>GetListOfStates(string[] stateNames,int[] statePopulations){return stateNames.Zip(statePopulations,(name, population)=>newState(){Name= name,Population= population
});}
Ich mochte diese Antwort auch, weil sie die Ähnlichkeit mitSelect
iliketocode
17
Lassen ZipSie sich NICHT vom Namen abschrecken. Es hat nichts mit dem Komprimieren zu tun, wie beim Komprimieren einer Datei oder eines Ordners (Komprimieren). Es hat seinen Namen von der Funktionsweise eines Reißverschlusses an der Kleidung: Der Reißverschluss an der Kleidung hat zwei Seiten und jede Seite hat ein paar Zähne. Wenn Sie in eine Richtung gehen, zählt der Reißverschluss beide Seiten auf (fährt) und schließt den Reißverschluss durch Zusammenbeißen der Zähne. Wenn Sie in die andere Richtung gehen, werden die Zähne geöffnet. Sie enden entweder mit einem offenen oder einem geschlossenen Reißverschluss.
Es ist die gleiche Idee mit der ZipMethode. Stellen Sie sich ein Beispiel vor, in dem wir zwei Sammlungen haben. Einer enthält Buchstaben und der andere den Namen eines Lebensmittels, das mit diesem Buchstaben beginnt. Aus Gründen der Klarheit rufe ich sie an leftSideOfZipperund rightSideOfZipper. Hier ist der Code.
var leftSideOfZipper =newList<string>{"A","B","C","D","E"};var rightSideOfZipper =newList<string>{"Apple","Banana","Coconut","Donut"};
Unsere Aufgabe ist es, eine Sammlung zu erstellen, bei der der Buchstabe der Frucht durch a :und ihren Namen getrennt ist. So was:
A :Apple
B :Banana
C :Coconut
D :Donut
Zipzur Rettung. Um mit unserer Reißverschluss-Terminologie Schritt zu halten, werden wir dieses Ergebnis closedZipperund die Elemente des linken Reißverschlusses leftToothund die rechte Seite righToothaus offensichtlichen Gründen aufrufen :
Oben zählen wir die linke Seite des Reißverschlusses und die rechte Seite des Reißverschlusses auf (bewegen) und führen eine Operation an jedem Zahn durch. Die Operation, die wir durchführen, besteht darin, den linken Zahn (Lebensmittelbuchstabe) mit einem :und dann den rechten Zahn (Lebensmittelname) zu verketten . Wir machen das mit diesem Code:
Wenn Sie einen echten Kleidungsreißverschluss aufzählen (ziehen) und eine Seite, egal ob die linke oder die rechte Seite, weniger Zähne als die andere Seite hat, was passiert dann? Nun, der Reißverschluss wird dort anhalten. Die ZipMethode macht genau das Gleiche: Sie stoppt, sobald sie das letzte Element auf beiden Seiten erreicht hat. In unserem Fall hat die rechte Seite weniger Zähne (Nahrungsnamen), so dass sie bei "Donut" endet.
+1. Ja, der Name "Zip" kann zunächst verwirrend sein. Vielleicht wären "Interleave" oder "Weave" aussagekräftigere Namen für die Methode gewesen.
Speck
1
@bacon ja, aber dann hätte ich mein Reißverschluss-Beispiel nicht verwenden können;) Ich denke, wenn Sie einmal herausgefunden haben, dass es wie ein Reißverschluss ist, ist es danach ziemlich einfach.
CodingYoshi
Obwohl ich genau wusste, was die Zip-Erweiterungsmethode bewirkt, war ich immer neugierig, warum sie so benannt wurde. Im allgemeinen Jargon der Software hat zip immer etwas anderes bedeutet. Tolle Analogie :-) Du musst die Gedanken des Schöpfers gelesen haben.
Raghu Reddy Muttana
7
Ich habe nicht die Wiederholungspunkte, die ich im Kommentarbereich posten kann, sondern um die entsprechende Frage zu beantworten:
Was ist, wenn Zip fortgesetzt werden soll, wenn in einer Liste keine Elemente mehr vorhanden sind? In diesem Fall sollte das kürzere Listenelement den Standardwert annehmen. Die Ausgabe erfolgt in diesem Fall A1, B2, C3, D0, E0. - Liang 19. November 15 um 3:29
Sie würden Array.Resize () verwenden, um die kürzere Sequenz mit Standardwerten aufzufüllen und sie dann zusammen zu zip ().
Codebeispiel:
var letters =newstring[]{"A","B","C","D","E"};var numbers =newint[]{1,2,3};if(numbers.Length< letters.Length)Array.Resize(ref numbers, letters.Length);var q = letters.Zip(numbers,(l, n)=> l + n.ToString());foreach(var s in q)Console.WriteLine(s);
Ausgabe:
A1
B2
C3
D0
E0
Bitte beachten Sie, dass die Verwendung von Array.Resize () eine Einschränkung hat : Redim Preserve in C #?
Wenn nicht bekannt ist, welche Sequenz die kürzere sein wird, kann eine Funktion erstellt werden, die sie zusammenfasst:
staticvoidMain(string[] args){var letters =newstring[]{"A","B","C","D","E"};var numbers =newint[]{1,2,3};var q = letters.Zip(numbers,(l, n)=> l + n.ToString()).ToArray();var qDef =ZipDefault(letters, numbers);Array.Resize(ref q, qDef.Count());// Note: using a second .Zip() to show the results side-by-sideforeach(var s in q.Zip(qDef,(a, b)=>string.Format("{0, 2} {1, 2}", a, b)))Console.WriteLine(s);}staticIEnumerable<string>ZipDefault(string[] letters,int[] numbers){switch(letters.Length.CompareTo(numbers.Length)){case-1:Array.Resize(ref letters, numbers.Length);break;case0:gotodefault;case1:Array.Resize(ref numbers, letters.Length);break;default:break;}return letters.Zip(numbers,(l, n)=> l + n.ToString());}
Ausgabe von Plain .Zip () neben ZipDefault ():
A1 A1
B2 B2
C3 C3
D0
E0
Zurück zur Hauptantwort der ursprünglichen Frage : Eine weitere interessante Sache, die man möglicherweise tun möchte (wenn die Längen der zu "komprimierenden" Sequenzen unterschiedlich sind), besteht darin, sie so zu verbinden, dass das Ende der Liste erreicht wird Streichhölzer statt oben. Dies kann erreicht werden, indem die entsprechende Anzahl von Elementen mit .Skip () "übersprungen" wird.
foreach(var s in letters.Skip(letters.Length- numbers.Length).Zip(numbers,(l, n)=> l + n.ToString()).ToArray())Console.WriteLine(s);
Das Ändern der Größe ist verschwenderisch, insbesondere wenn eine der Sammlungen groß ist. Was Sie wirklich tun möchten, ist eine Aufzählung, die nach dem Ende der Sammlung fortgesetzt wird und bei Bedarf mit leeren Werten gefüllt wird (ohne Hintergrundsammlung). Sie können das tun mit: public static IEnumerable<T> Pad<T>(this IEnumerable<T> input, long minLength, T value = default(T)) { long numYielded = 0; foreach (T element in input) { yield return element; ++numYielded; } while (numYielded < minLength) { yield return value; ++numYielded; } }
Pagefault
Ich bin mir nicht sicher, wie ich Code in einem Kommentar erfolgreich formatieren soll ...
Pagefault
7
Viele der Antworten hier zeigen Zip, aber ohne wirklich einen realen Anwendungsfall zu erklären, der die Verwendung von motivieren würde Zip.
Ein besonders häufiges Muster, das Zipsich hervorragend zum Durchlaufen aufeinanderfolgender Paar von Dingen eignet. Dies erfolgt durch Iteration einer Aufzählung Xmit sich selbst, wobei 1 Element übersprungen wird : x.Zip(x.Skip(1). Visuelles Beispiel:
x | x.Skip(1)| x.Zip(x.Skip(1),...)---+-----------+----------------------|1|1|2|(1,2)2|3|(2,1)3|4|(3,2)4|5|(4,3)
Diese aufeinanderfolgenden Paare sind nützlich, um die ersten Unterschiede zwischen Werten zu finden. Zum Beispiel können aufeinanderfolgende Paare von IEnumable<MouseXPosition>verwendet werden, um zu produzieren IEnumerable<MouseXDelta>. In ähnlicher Weise können abgetastete boolWerte von a buttonin Ereignisse wie NotPressed/ Clicked/ Held/ interpretiert werden Released. Diese Ereignisse können dann Aufrufe zum Delegieren von Methoden auslösen. Hier ist ein Beispiel:
using System;
using System.Collections.Generic;
using System.Linq;enumMouseEvent{NotPressed,Clicked,Held,Released}publicclassProgram{publicstaticvoidMain(){// Example: Sampling the boolean state of a mouse buttonList<bool> mouseStates =newList<bool>{false,false,false,false,true,true,true,false,true,false,false,true};
mouseStates.Zip(mouseStates.Skip(1),(oldMouseState, newMouseState)=>{if(oldMouseState){if(newMouseState)returnMouseEvent.Held;elsereturnMouseEvent.Released;}else{if(newMouseState)returnMouseEvent.Clicked;elsereturnMouseEvent.NotPressed;}}).ToList().ForEach(mouseEvent =>Console.WriteLine(mouseEvent));}}
Wie bereits erwähnt, können Sie mit Zip zwei Sammlungen zur Verwendung in weiteren Linq-Anweisungen oder einer foreach-Schleife kombinieren.
Vorgänge, für die früher eine for-Schleife und zwei Arrays erforderlich waren, können jetzt in einer foreach-Schleife mit einem anonymen Objekt ausgeführt werden.
Ein Beispiel, das ich gerade entdeckt habe, das irgendwie albern ist, aber nützlich sein könnte, wenn die Parallelisierung vorteilhaft wäre, wäre eine Warteschlangenüberquerung mit einer Zeile mit Nebenwirkungen:
timeSegments repräsentiert die aktuellen oder in die Warteschlange gestellten Elemente in einer Warteschlange (das letzte Element wird von Zip abgeschnitten). timeSegments.Skip (1) repräsentiert die nächsten oder Peek-Elemente in einer Warteschlange. Die Zip-Methode kombiniert diese beiden zu einem einzigen anonymen Objekt mit den Eigenschaften Next und Current. Dann filtern wir mit Where und nehmen Änderungen mit AsParallel () vor. ForAll. Natürlich kann das letzte Bit nur eine reguläre foreach- oder eine andere Select-Anweisung sein, die die fehlerhaften Zeitsegmente zurückgibt.
Mit der Zip-Methode können Sie zwei nicht verwandte Sequenzen mithilfe eines Anbieters für Zusammenführungsfunktionen von Ihnen, dem Anrufer, "zusammenführen". Das Beispiel auf MSDN zeigt ziemlich gut, was Sie mit Zip tun können. In diesem Beispiel nehmen Sie zwei beliebige, nicht verwandte Sequenzen und kombinieren sie mit einer beliebigen Funktion (in diesem Fall verketten Sie nur Elemente aus beiden Sequenzen zu einer einzigen Zeichenfolge).
int[] numbers ={1,2,3,4};string[] words ={"one","two","three"};var numbersAndWords = numbers.Zip(words,(first, second)=> first +" "+ second);foreach(var item in numbersAndWords)Console.WriteLine(item);// This code produces the following output:// 1 one// 2 two// 3 three
Antworten:
Der Zip-Operator führt die entsprechenden Elemente zweier Sequenzen mithilfe einer angegebenen Auswahlfunktion zusammen.
Ausgabe
quelle
Zip
Alternative. B) Schreiben auf ein Verfahrenyield return
jedes Element der kürzeren Liste, und dann weiteryield return
ing aufdefault
unbestimmte Zeit danach. (Option B erfordert, dass Sie im Voraus wissen, welche Liste kürzer ist.)Zip
dient zum Kombinieren von zwei Sequenzen zu einer. Zum Beispiel, wenn Sie die Sequenzen habenund
und Sie möchten die Sequenz erhalten, die das Ergebnis der Multiplikation von Elementen an derselben Position in jeder Sequenz ist
du könntest sagen
Es wird als "Reißverschluss" bezeichnet, da Sie sich eine Sequenz als die linke Seite eines Reißverschlusses und die andere Sequenz als die rechte Seite des Reißverschlusses vorstellen Elemente der Sequenz) angemessen.
quelle
Es durchläuft zwei Sequenzen und kombiniert ihre Elemente nacheinander zu einer einzigen neuen Sequenz. Sie nehmen also ein Element der Sequenz A, transformieren es mit dem entsprechenden Element aus Sequenz B und das Ergebnis bildet ein Element der Sequenz C.
Eine Möglichkeit, darüber nachzudenken, besteht darin, dass es ähnlich ist
Select
, außer dass Elemente aus einer einzelnen Sammlung transformiert werden und zwei Sammlungen gleichzeitig bearbeitet werden.Aus dem MSDN-Artikel zur Methode :
Wenn Sie dies in imperativem Code tun würden, würden Sie wahrscheinlich Folgendes tun:
Oder wenn LINQ nicht
Zip
drin wäre, könnten Sie dies tun:Dies ist nützlich, wenn Sie Daten in einfachen, Array-ähnlichen Listen mit jeweils gleicher Länge und Reihenfolge verteilen und jeweils eine andere Eigenschaft derselben Objektgruppe beschreiben.
Zip
hilft Ihnen, diese Daten zu einer kohärenteren Struktur zusammenzufügen.Wenn Sie also ein Array von Statusnamen und ein anderes Array ihrer Abkürzungen haben, können Sie diese
State
wie folgt zu einer Klasse zusammenfassen:quelle
Select
Lassen
Zip
Sie sich NICHT vom Namen abschrecken. Es hat nichts mit dem Komprimieren zu tun, wie beim Komprimieren einer Datei oder eines Ordners (Komprimieren). Es hat seinen Namen von der Funktionsweise eines Reißverschlusses an der Kleidung: Der Reißverschluss an der Kleidung hat zwei Seiten und jede Seite hat ein paar Zähne. Wenn Sie in eine Richtung gehen, zählt der Reißverschluss beide Seiten auf (fährt) und schließt den Reißverschluss durch Zusammenbeißen der Zähne. Wenn Sie in die andere Richtung gehen, werden die Zähne geöffnet. Sie enden entweder mit einem offenen oder einem geschlossenen Reißverschluss.Es ist die gleiche Idee mit der
Zip
Methode. Stellen Sie sich ein Beispiel vor, in dem wir zwei Sammlungen haben. Einer enthält Buchstaben und der andere den Namen eines Lebensmittels, das mit diesem Buchstaben beginnt. Aus Gründen der Klarheit rufe ich sie anleftSideOfZipper
undrightSideOfZipper
. Hier ist der Code.Unsere Aufgabe ist es, eine Sammlung zu erstellen, bei der der Buchstabe der Frucht durch a
:
und ihren Namen getrennt ist. So was:Zip
zur Rettung. Um mit unserer Reißverschluss-Terminologie Schritt zu halten, werden wir dieses ErgebnisclosedZipper
und die Elemente des linken ReißverschlussesleftTooth
und die rechte SeiterighTooth
aus offensichtlichen Gründen aufrufen :Oben zählen wir die linke Seite des Reißverschlusses und die rechte Seite des Reißverschlusses auf (bewegen) und führen eine Operation an jedem Zahn durch. Die Operation, die wir durchführen, besteht darin, den linken Zahn (Lebensmittelbuchstabe) mit einem
:
und dann den rechten Zahn (Lebensmittelname) zu verketten . Wir machen das mit diesem Code:Das Endergebnis ist folgendes:
Was ist mit dem letzten Buchstaben E passiert?
Wenn Sie einen echten Kleidungsreißverschluss aufzählen (ziehen) und eine Seite, egal ob die linke oder die rechte Seite, weniger Zähne als die andere Seite hat, was passiert dann? Nun, der Reißverschluss wird dort anhalten. Die
Zip
Methode macht genau das Gleiche: Sie stoppt, sobald sie das letzte Element auf beiden Seiten erreicht hat. In unserem Fall hat die rechte Seite weniger Zähne (Nahrungsnamen), so dass sie bei "Donut" endet.quelle
Ich habe nicht die Wiederholungspunkte, die ich im Kommentarbereich posten kann, sondern um die entsprechende Frage zu beantworten:
Sie würden Array.Resize () verwenden, um die kürzere Sequenz mit Standardwerten aufzufüllen und sie dann zusammen zu zip ().
Codebeispiel:
Ausgabe:
Bitte beachten Sie, dass die Verwendung von Array.Resize () eine Einschränkung hat : Redim Preserve in C #?
Wenn nicht bekannt ist, welche Sequenz die kürzere sein wird, kann eine Funktion erstellt werden, die sie zusammenfasst:
Ausgabe von Plain .Zip () neben ZipDefault ():
Zurück zur Hauptantwort der ursprünglichen Frage : Eine weitere interessante Sache, die man möglicherweise tun möchte (wenn die Längen der zu "komprimierenden" Sequenzen unterschiedlich sind), besteht darin, sie so zu verbinden, dass das Ende der Liste erreicht wird Streichhölzer statt oben. Dies kann erreicht werden, indem die entsprechende Anzahl von Elementen mit .Skip () "übersprungen" wird.
Ausgabe:
quelle
public static IEnumerable<T> Pad<T>(this IEnumerable<T> input, long minLength, T value = default(T)) { long numYielded = 0; foreach (T element in input) { yield return element; ++numYielded; } while (numYielded < minLength) { yield return value; ++numYielded; } }
Viele der Antworten hier zeigen
Zip
, aber ohne wirklich einen realen Anwendungsfall zu erklären, der die Verwendung von motivieren würdeZip
.Ein besonders häufiges Muster, das
Zip
sich hervorragend zum Durchlaufen aufeinanderfolgender Paar von Dingen eignet. Dies erfolgt durch Iteration einer AufzählungX
mit sich selbst, wobei 1 Element übersprungen wird :x.Zip(x.Skip(1)
. Visuelles Beispiel:Diese aufeinanderfolgenden Paare sind nützlich, um die ersten Unterschiede zwischen Werten zu finden. Zum Beispiel können aufeinanderfolgende Paare von
IEnumable<MouseXPosition>
verwendet werden, um zu produzierenIEnumerable<MouseXDelta>
. In ähnlicher Weise können abgetastetebool
Werte von abutton
in Ereignisse wieNotPressed
/Clicked
/Held
/ interpretiert werdenReleased
. Diese Ereignisse können dann Aufrufe zum Delegieren von Methoden auslösen. Hier ist ein Beispiel:Drucke:
quelle
Wie bereits erwähnt, können Sie mit Zip zwei Sammlungen zur Verwendung in weiteren Linq-Anweisungen oder einer foreach-Schleife kombinieren.
Vorgänge, für die früher eine for-Schleife und zwei Arrays erforderlich waren, können jetzt in einer foreach-Schleife mit einem anonymen Objekt ausgeführt werden.
Ein Beispiel, das ich gerade entdeckt habe, das irgendwie albern ist, aber nützlich sein könnte, wenn die Parallelisierung vorteilhaft wäre, wäre eine Warteschlangenüberquerung mit einer Zeile mit Nebenwirkungen:
timeSegments repräsentiert die aktuellen oder in die Warteschlange gestellten Elemente in einer Warteschlange (das letzte Element wird von Zip abgeschnitten). timeSegments.Skip (1) repräsentiert die nächsten oder Peek-Elemente in einer Warteschlange. Die Zip-Methode kombiniert diese beiden zu einem einzigen anonymen Objekt mit den Eigenschaften Next und Current. Dann filtern wir mit Where und nehmen Änderungen mit AsParallel () vor. ForAll. Natürlich kann das letzte Bit nur eine reguläre foreach- oder eine andere Select-Anweisung sein, die die fehlerhaften Zeitsegmente zurückgibt.
quelle
Mit der Zip-Methode können Sie zwei nicht verwandte Sequenzen mithilfe eines Anbieters für Zusammenführungsfunktionen von Ihnen, dem Anrufer, "zusammenführen". Das Beispiel auf MSDN zeigt ziemlich gut, was Sie mit Zip tun können. In diesem Beispiel nehmen Sie zwei beliebige, nicht verwandte Sequenzen und kombinieren sie mit einer beliebigen Funktion (in diesem Fall verketten Sie nur Elemente aus beiden Sequenzen zu einer einzigen Zeichenfolge).
quelle
quelle