Operator Zip menggabungkan elemen yang sesuai dari dua urutan menggunakan fungsi pemilih yang ditentukan.
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);
Saya suka jawaban ini karena ini menunjukkan apa yang terjadi ketika jumlah elemen tidak cocok, mirip dengan dokumentasi
msdn
2
bagaimana jika saya ingin zip melanjutkan di mana satu daftar kehabisan elemen? dalam hal ini elemen daftar pendek harus mengambil nilai default. Output dalam hal ini adalah A1, B2, C3, D0, E0.
liang
2
@liang Dua pilihan: A) Tuliskan Zipalternatif Anda sendiri . B) Write metode untuk yield returnsetiap elemen dari daftar pendek, dan kemudian melanjutkan yield returning defaulttanpa batas setelahnya. (Opsi B mengharuskan Anda untuk mengetahui terlebih dahulu daftar mana yang lebih pendek.)
jpaugh
105
Zipadalah untuk menggabungkan dua urutan menjadi satu. Misalnya, jika Anda memiliki urutan
1,2,3
dan
10,20,30
dan Anda ingin urutan yang merupakan hasil dari mengalikan elemen di posisi yang sama di setiap urutan untuk memperoleh
10,40,90
Anda bisa mengatakan
var left =new[]{1,2,3};var right =new[]{10,20,30};var products = left.Zip(right,(m, n)=> m * n);
Ini disebut "zip" karena Anda menganggap satu urutan sebagai sisi kiri ritsleting, dan urutan lainnya sebagai sisi kanan ritsleting, dan operator zip akan menarik kedua sisi bersama-sama berpasangan dari gigi ( elemen urutan) dengan tepat.
Mencintai contoh ritsleting. Itu sangat alami. Kesan awal saya adalah apakah itu ada hubungannya dengan kecepatan atau sesuatu seperti itu seolah-olah Anda melewati jalanan di mobil Anda.
RBT
23
Iterates melalui dua urutan dan menggabungkan elemen-elemen mereka, satu per satu, menjadi satu urutan baru. Jadi Anda mengambil elemen urutan A, mentransformasikannya dengan elemen yang sesuai dari urutan B, dan hasilnya membentuk elemen urutan C.
Salah satu cara untuk memikirkannya adalah bahwa itu mirip dengan Select, kecuali alih-alih mengubah item dari satu koleksi, itu berfungsi pada dua koleksi sekaligus.
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
Jika Anda melakukan ini dalam kode imperatif, Anda mungkin akan melakukan sesuatu seperti ini:
for(int i =0; i < numbers.Length&& i < words.Length; i++){
numbersAndWords.Add(numbers[i]+" "+ words[i]);}
Atau jika LINQ tidak ada Zipdi dalamnya, Anda bisa melakukan ini:
var numbersAndWords = numbers.Select((num, i)=> num +" "+ words[i]);
Ini berguna ketika Anda memiliki data yang menyebar ke daftar sederhana, seperti array, masing-masing dengan panjang dan urutan yang sama, dan masing-masing menggambarkan properti berbeda dari set objek yang sama. Zipmembantu Anda menyatukan potongan-potongan data menjadi struktur yang lebih koheren.
Jadi jika Anda memiliki larik nama negara dan larik singkatan lainnya, Anda bisa menyusunnya menjadi Statekelas seperti:
IEnumerable<State>GetListOfStates(string[] stateNames,int[] statePopulations){return stateNames.Zip(statePopulations,(name, population)=>newState(){Name= name,Population= population
});}
Saya juga menyukai jawaban ini, karena menyebutkan kemiripan denganSelect
iliketocode
17
JANGAN biarkan nama itu Zipmengusir Anda. Ini tidak ada hubungannya dengan zip seperti dalam zip file atau folder (mengompresi). Ini sebenarnya mendapatkan namanya dari bagaimana ritsleting pada pakaian bekerja: Ritsleting pada pakaian memiliki 2 sisi dan setiap sisi memiliki banyak gigi. Ketika Anda pergi dalam satu arah, ritsleting menyebutkan (perjalanan) kedua sisi dan menutup ritsleting dengan mengepalkan gigi. Ketika Anda pergi ke arah lain itu membuka gigi. Anda bisa mengakhiri dengan ritsleting terbuka atau tertutup.
Itu adalah ide yang sama dengan Zipmetodenya. Perhatikan contoh di mana kami memiliki dua koleksi. Satu memegang surat dan yang lainnya memegang nama item makanan yang dimulai dengan surat itu. Untuk tujuan kejelasan saya memanggil mereka leftSideOfZipperdan rightSideOfZipper. Ini kodenya.
var leftSideOfZipper =newList<string>{"A","B","C","D","E"};var rightSideOfZipper =newList<string>{"Apple","Banana","Coconut","Donut"};
Tugas kita adalah menghasilkan satu koleksi yang memiliki huruf buah yang dipisahkan oleh :dan namanya. Seperti ini:
A :Apple
B :Banana
C :Coconut
D :Donut
Zipuntuk menyelamatkan. Untuk mengikuti terminologi ritsleting kami, kami akan memanggil hasil ini closedZipperdan item dari ritsleting kiri akan kami panggil leftToothdan sisi kanan kami akan memanggil righToothuntuk alasan yang jelas:
Di atas kita menghitung (bepergian) sisi kiri ritsleting dan sisi kanan ritsleting dan melakukan operasi pada setiap gigi. Operasi yang kami lakukan adalah menggabungkan gigi kiri (surat makanan) dengan :dan kemudian gigi kanan (nama makanan). Kami melakukannya dengan menggunakan kode ini:
Jika Anda menghitung (menarik) ritsleting pakaian asli dan satu sisi, tidak masalah sisi kiri atau sisi kanan, memiliki lebih sedikit gigi daripada sisi lainnya, apa yang akan terjadi? Ritsleting akan berhenti di situ. The ZipMetode akan melakukan persis sama: Ini akan berhenti setelah mencapai item terakhir di kedua sisi. Dalam kasus kami sisi kanan memiliki lebih sedikit gigi (nama makanan) sehingga akan berhenti di "Donat".
+1. Ya, nama "Zip" bisa membingungkan pada awalnya. Mungkin "Interleave" atau "Weave" akan menjadi nama yang lebih deskriptif untuk metode ini.
BACON
1
@ daging ya tapi kemudian saya tidak akan bisa menggunakan contoh ritsleting saya;) Saya pikir begitu Anda tahu itu seperti ritsleting, itu cukup lurus ke depan setelah itu.
CodingYoshi
Meskipun saya tahu persis apa metode ekstensi Zip tidak, saya selalu ingin tahu mengapa itu dinamai begitu. Dalam jargon umum perangkat lunak zip selalu berarti sesuatu yang lain. Analogi yang bagus :-) Anda pasti sudah membaca pikiran pencipta.
Raghu Reddy Muttana
7
Saya tidak memiliki poin perwakilan untuk dikirim di bagian komentar, tetapi untuk menjawab pertanyaan terkait:
Bagaimana jika saya ingin zip melanjutkan di mana satu daftar kehabisan elemen? Dalam hal ini elemen daftar pendek harus mengambil nilai default. Output dalam hal ini adalah A1, B2, C3, D0, E0. - liang 19 Nov '15 jam 3:29
Apa yang akan Anda lakukan adalah menggunakan Array.Resize () untuk pad-out urutan yang lebih pendek dengan nilai default, dan kemudian Zip () bersama-sama.
Contoh kode:
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);
Jika tidak diketahui urutan mana yang akan menjadi lebih pendek, sebuah fungsi dapat dibuat yang mengikutinya:
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());}
Output dari .Zip () bersama ZipDefault ():
A1 A1
B2 B2
C3 C3
D0
E0
Kembali ke jawaban utama dari pertanyaan awal , hal menarik lain yang mungkin ingin dilakukan seseorang (ketika panjang urutan "zip" berbeda) adalah bergabung dengan mereka sedemikian rupa sehingga akhir daftar cocok bukan bagian atas. Ini dapat dilakukan dengan "melompati" jumlah item yang sesuai menggunakan .Skip ().
foreach(var s in letters.Skip(letters.Length- numbers.Length).Zip(numbers,(l, n)=> l + n.ToString()).ToArray())Console.WriteLine(s);
Ubah ukuran adalah sia-sia, terutama jika salah satu koleksi besar. Apa yang benar-benar ingin Anda lakukan adalah memiliki penghitungan yang berlanjut setelah akhir koleksi, mengisinya dengan nilai kosong sesuai permintaan (tanpa koleksi dukungan). Anda dapat melakukannya dengan: 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
Sepertinya saya tidak yakin bagaimana cara memformat kode dalam komentar ...
Pagefault
7
Banyak jawaban di sini menunjukkan Zip, tetapi tanpa benar-benar menjelaskan kasus penggunaan kehidupan nyata yang akan memotivasi penggunaan Zip.
Salah satu pola umum yang Zipfantastis untuk mengulangi hal-hal yang berurutan. Hal ini dilakukan dengan iterasi sebuah enumerable Xdengan dirinya sendiri, melompat-lompat 1 elemen: x.Zip(x.Skip(1). Contoh Visual:
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)
Pasangan berturut-turut ini berguna untuk menemukan perbedaan pertama antara nilai. Misalnya, pasangan berturut-turut IEnumable<MouseXPosition>dapat digunakan untuk menghasilkan IEnumerable<MouseXDelta>. Demikian pula, boolnilai sampel dari a buttondapat diinterpretasikan ke dalam peristiwa seperti NotPressed/ Clicked/ Held/ Released. Acara-acara tersebut kemudian dapat mendorong panggilan untuk mendelegasikan metode. Ini sebuah contoh:
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));}}
Seperti yang telah dinyatakan orang lain, Zip memungkinkan Anda menggabungkan dua koleksi untuk digunakan dalam pernyataan Linq lebih lanjut atau loop foreach.
Operasi yang dulu memerlukan for for loop dan dua array sekarang dapat dilakukan dalam foreach loop menggunakan objek anonim.
Contoh yang baru saja saya temukan, itu agak konyol, tetapi bisa berguna jika paralelisasi bermanfaat akan menjadi satu baris Antrian traversal dengan efek samping:
timeSegments merepresentasikan item saat ini atau dequeued dalam antrian (elemen terakhir dipotong oleh Zip). timeSegments.Skip (1) mewakili item berikutnya atau mengintip dalam antrian. Metode Zip menggabungkan keduanya menjadi objek anonim tunggal dengan properti Berikutnya dan Sekarang. Lalu kami memfilter dengan Di mana dan melakukan perubahan dengan AsParallel (). ForAll. Tentu saja bit terakhir hanya bisa menjadi foreach biasa atau pernyataan Select lain yang mengembalikan segmen waktu yang menyinggung.
Metode Zip memungkinkan Anda untuk "menggabungkan" dua urutan yang tidak terkait, menggunakan penyedia fungsi penggabungan oleh Anda, pemanggil. Contoh pada MSDN sebenarnya cukup bagus untuk menunjukkan apa yang dapat Anda lakukan dengan Zip. Dalam contoh ini, Anda mengambil dua urutan yang arbitrer dan tidak terkait, dan menggabungkannya menggunakan fungsi arbitrer (dalam hal ini, hanya menggabungkan item dari kedua urutan menjadi string tunggal).
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
Jawaban:
Operator Zip menggabungkan elemen yang sesuai dari dua urutan menggunakan fungsi pemilih yang ditentukan.
Ouput
sumber
Zip
alternatif Anda sendiri . B) Write metode untukyield return
setiap elemen dari daftar pendek, dan kemudian melanjutkanyield return
ingdefault
tanpa batas setelahnya. (Opsi B mengharuskan Anda untuk mengetahui terlebih dahulu daftar mana yang lebih pendek.)Zip
adalah untuk menggabungkan dua urutan menjadi satu. Misalnya, jika Anda memiliki urutandan
dan Anda ingin urutan yang merupakan hasil dari mengalikan elemen di posisi yang sama di setiap urutan untuk memperoleh
Anda bisa mengatakan
Ini disebut "zip" karena Anda menganggap satu urutan sebagai sisi kiri ritsleting, dan urutan lainnya sebagai sisi kanan ritsleting, dan operator zip akan menarik kedua sisi bersama-sama berpasangan dari gigi ( elemen urutan) dengan tepat.
sumber
Iterates melalui dua urutan dan menggabungkan elemen-elemen mereka, satu per satu, menjadi satu urutan baru. Jadi Anda mengambil elemen urutan A, mentransformasikannya dengan elemen yang sesuai dari urutan B, dan hasilnya membentuk elemen urutan C.
Salah satu cara untuk memikirkannya adalah bahwa itu mirip dengan
Select
, kecuali alih-alih mengubah item dari satu koleksi, itu berfungsi pada dua koleksi sekaligus.Dari artikel MSDN pada metode :
Jika Anda melakukan ini dalam kode imperatif, Anda mungkin akan melakukan sesuatu seperti ini:
Atau jika LINQ tidak ada
Zip
di dalamnya, Anda bisa melakukan ini:Ini berguna ketika Anda memiliki data yang menyebar ke daftar sederhana, seperti array, masing-masing dengan panjang dan urutan yang sama, dan masing-masing menggambarkan properti berbeda dari set objek yang sama.
Zip
membantu Anda menyatukan potongan-potongan data menjadi struktur yang lebih koheren.Jadi jika Anda memiliki larik nama negara dan larik singkatan lainnya, Anda bisa menyusunnya menjadi
State
kelas seperti:sumber
Select
JANGAN biarkan nama itu
Zip
mengusir Anda. Ini tidak ada hubungannya dengan zip seperti dalam zip file atau folder (mengompresi). Ini sebenarnya mendapatkan namanya dari bagaimana ritsleting pada pakaian bekerja: Ritsleting pada pakaian memiliki 2 sisi dan setiap sisi memiliki banyak gigi. Ketika Anda pergi dalam satu arah, ritsleting menyebutkan (perjalanan) kedua sisi dan menutup ritsleting dengan mengepalkan gigi. Ketika Anda pergi ke arah lain itu membuka gigi. Anda bisa mengakhiri dengan ritsleting terbuka atau tertutup.Itu adalah ide yang sama dengan
Zip
metodenya. Perhatikan contoh di mana kami memiliki dua koleksi. Satu memegang surat dan yang lainnya memegang nama item makanan yang dimulai dengan surat itu. Untuk tujuan kejelasan saya memanggil merekaleftSideOfZipper
danrightSideOfZipper
. Ini kodenya.Tugas kita adalah menghasilkan satu koleksi yang memiliki huruf buah yang dipisahkan oleh
:
dan namanya. Seperti ini:Zip
untuk menyelamatkan. Untuk mengikuti terminologi ritsleting kami, kami akan memanggil hasil iniclosedZipper
dan item dari ritsleting kiri akan kami panggilleftTooth
dan sisi kanan kami akan memanggilrighTooth
untuk alasan yang jelas:Di atas kita menghitung (bepergian) sisi kiri ritsleting dan sisi kanan ritsleting dan melakukan operasi pada setiap gigi. Operasi yang kami lakukan adalah menggabungkan gigi kiri (surat makanan) dengan
:
dan kemudian gigi kanan (nama makanan). Kami melakukannya dengan menggunakan kode ini:Hasil akhirnya adalah ini:
Apa yang terjadi pada huruf E terakhir?
Jika Anda menghitung (menarik) ritsleting pakaian asli dan satu sisi, tidak masalah sisi kiri atau sisi kanan, memiliki lebih sedikit gigi daripada sisi lainnya, apa yang akan terjadi? Ritsleting akan berhenti di situ. The
Zip
Metode akan melakukan persis sama: Ini akan berhenti setelah mencapai item terakhir di kedua sisi. Dalam kasus kami sisi kanan memiliki lebih sedikit gigi (nama makanan) sehingga akan berhenti di "Donat".sumber
Saya tidak memiliki poin perwakilan untuk dikirim di bagian komentar, tetapi untuk menjawab pertanyaan terkait:
Apa yang akan Anda lakukan adalah menggunakan Array.Resize () untuk pad-out urutan yang lebih pendek dengan nilai default, dan kemudian Zip () bersama-sama.
Contoh kode:
Keluaran:
Harap dicatat bahwa menggunakan Array.Resize () memiliki peringatan : Redim Preserve dalam C #?
Jika tidak diketahui urutan mana yang akan menjadi lebih pendek, sebuah fungsi dapat dibuat yang mengikutinya:
Output dari .Zip () bersama ZipDefault ():
Kembali ke jawaban utama dari pertanyaan awal , hal menarik lain yang mungkin ingin dilakukan seseorang (ketika panjang urutan "zip" berbeda) adalah bergabung dengan mereka sedemikian rupa sehingga akhir daftar cocok bukan bagian atas. Ini dapat dilakukan dengan "melompati" jumlah item yang sesuai menggunakan .Skip ().
Keluaran:
sumber
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; } }
Banyak jawaban di sini menunjukkan
Zip
, tetapi tanpa benar-benar menjelaskan kasus penggunaan kehidupan nyata yang akan memotivasi penggunaanZip
.Salah satu pola umum yang
Zip
fantastis untuk mengulangi hal-hal yang berurutan. Hal ini dilakukan dengan iterasi sebuah enumerableX
dengan dirinya sendiri, melompat-lompat 1 elemen:x.Zip(x.Skip(1)
. Contoh Visual:Pasangan berturut-turut ini berguna untuk menemukan perbedaan pertama antara nilai. Misalnya, pasangan berturut-turut
IEnumable<MouseXPosition>
dapat digunakan untuk menghasilkanIEnumerable<MouseXDelta>
. Demikian pula,bool
nilai sampel dari abutton
dapat diinterpretasikan ke dalam peristiwa sepertiNotPressed
/Clicked
/Held
/Released
. Acara-acara tersebut kemudian dapat mendorong panggilan untuk mendelegasikan metode. Ini sebuah contoh:Cetakan:
sumber
Seperti yang telah dinyatakan orang lain, Zip memungkinkan Anda menggabungkan dua koleksi untuk digunakan dalam pernyataan Linq lebih lanjut atau loop foreach.
Operasi yang dulu memerlukan for for loop dan dua array sekarang dapat dilakukan dalam foreach loop menggunakan objek anonim.
Contoh yang baru saja saya temukan, itu agak konyol, tetapi bisa berguna jika paralelisasi bermanfaat akan menjadi satu baris Antrian traversal dengan efek samping:
timeSegments merepresentasikan item saat ini atau dequeued dalam antrian (elemen terakhir dipotong oleh Zip). timeSegments.Skip (1) mewakili item berikutnya atau mengintip dalam antrian. Metode Zip menggabungkan keduanya menjadi objek anonim tunggal dengan properti Berikutnya dan Sekarang. Lalu kami memfilter dengan Di mana dan melakukan perubahan dengan AsParallel (). ForAll. Tentu saja bit terakhir hanya bisa menjadi foreach biasa atau pernyataan Select lain yang mengembalikan segmen waktu yang menyinggung.
sumber
Metode Zip memungkinkan Anda untuk "menggabungkan" dua urutan yang tidak terkait, menggunakan penyedia fungsi penggabungan oleh Anda, pemanggil. Contoh pada MSDN sebenarnya cukup bagus untuk menunjukkan apa yang dapat Anda lakukan dengan Zip. Dalam contoh ini, Anda mengambil dua urutan yang arbitrer dan tidak terkait, dan menggabungkannya menggunakan fungsi arbitrer (dalam hal ini, hanya menggabungkan item dari kedua urutan menjadi string tunggal).
sumber
sumber