Dengan loop for berbasis rentang baru kita dapat menulis kode seperti
for(auto x: Y) {}
IMO mana yang merupakan peningkatan besar dari (misalnya)
for(std::vector<int>::iterator x=Y.begin(); x!=Y.end(); ++x) {}
Bisakah itu digunakan untuk mengulang dua loop simultan, seperti zip
fungsi Pythons ? Bagi mereka yang tidak terbiasa dengan Python, kode:
Y1 = [1,2,3]
Y2 = [4,5,6,7]
for x1,x2 in zip(Y1,Y2):
print x1,x2
Memberikan sebagai keluaran (1,4) (2,5) (3,6)
for
hanya dapat digunakan dengan satu variabel, jadi tidak. Jika Anda ingin mengakses dua nilai sekaligus, Anda harus menggunakan sesuatu sepertistd::pair
zip()
fungsi yang mengembalikan tupel dan mengulang daftar tupel.for(;;)
bisa mendapatkan perilaku ini, meskipun jangka panjang, jadi pertanyaannya sebenarnya: Apakah mungkin untuk "otomatis" pada dua objek sekaligus?Jawaban:
Peringatan:
boost::zip_iterator
danboost::combine
pada Boost 1.63.0 (26 Des 2016) akan menyebabkan perilaku tidak terdefinisi jika panjang wadah masukan tidak sama (mungkin macet atau berulang setelah akhir).Mulai dari Boost 1.56.0 (2014 Agustus 7), Anda dapat menggunakan
boost::combine
(fungsi tersebut ada di versi sebelumnya tetapi tidak terdokumentasi):Ini akan mencetak
Di versi sebelumnya, Anda dapat menentukan sendiri rentang seperti ini:
Penggunaannya sama.
sumber
optional
elemen untuk kemungkinan iterasi terakhir ...Jadi saya menulis zip ini sebelumnya ketika saya bosan, saya memutuskan untuk mempostingnya karena berbeda dari yang lain karena tidak menggunakan boost dan lebih mirip c ++ stdlib.
Contoh penggunaan:
sumber
[](int i,int j,float k,float l)
kerjanya? Apakah ini fungsi lambda?std::for_each
tetapi Anda dapat menggunakan jumlah rentang yang sewenang-wenang, parameter di lambda bergantung pada berapa banyak iterator yang Anda berikan fungsistd :: transform dapat melakukan ini dengan mudah:
Jika urutan kedua lebih pendek, implementasi saya tampaknya memberikan nilai yang diinisialisasi default.
sumber
b
.Anda dapat menggunakan solusi berdasarkan
boost::zip_iterator
. Buat kelas container palsu yang memelihara referensi ke container Anda, dan yang mengembalikanzip_iterator
dari fungsi anggotabegin
danend
. Sekarang Anda bisa menulisContoh implementasi (harap diuji):
Saya tinggalkan versi variadic sebagai latihan yang sangat baik untuk pembaca.
sumber
boost::iterator_range
+boost::zip_iterator
, bahkan versi variadic.boost::zip_iterator
tidak bekerja dengan rentang dengan panjang yang berbedaLihat
<redi/zip.h>
untukzip
fungsi yang bekerja dengan rentang-basefor
dan menerima sejumlah rentang, yang dapat rvalues atau lvalues dan dapat panjang yang berbeda (iterasi akan berhenti pada akhir rentang terpendek).Cetakan
0 1 2 3 4 5
sumber
boost/tuple/tuple_io.hpp
untukcout << i;
boost::get<0>(i)
danboost::get<1>(i)
. Saya tidak yakin mengapa sampel asli tidak dapat diadaptasi secara langsung, mungkin ada hubungannya dengan fakta bahwa kode saya mengambil referensi konstan ke container.Dengan range-v3 :
Hasil:
sumber
Saya mengalami pertanyaan yang sama ini secara independen dan tidak menyukai sintaks dari semua yang disebutkan di atas. Jadi, saya memiliki file header pendek yang pada dasarnya melakukan hal yang sama dengan boost zip_iterator tetapi memiliki beberapa makro untuk membuat sintaksnya lebih enak bagi saya:
https://github.com/cshelton/zipfor
Misalnya Anda bisa melakukannya
Gula sintaksis utama adalah saya dapat memberi nama elemen dari setiap wadah. Saya juga menyertakan "mapfor" yang melakukan hal yang sama, tetapi untuk peta (untuk menamai elemen ".first" dan ".second").
sumber
sumber
Jika Anda suka kelebihan beban operator, berikut tiga kemungkinannya. Dua yang pertama menggunakan
std::pair<>
danstd::tuple<>
, masing-masing, sebagai iterator; yang ketiga memperluas ini ke berbasis jangkauanfor
. Perhatikan bahwa tidak semua orang akan menyukai definisi operator ini, jadi yang terbaik adalah menyimpannya di namespace terpisah dan memilikiusing namespace
fungsi (bukan file!) Di mana Anda ingin menggunakannya.sumber
Untuk pustaka pemrosesan aliran C ++ yang saya tulis, saya sedang mencari solusi yang tidak bergantung pada pustaka pihak ketiga dan bekerja dengan jumlah wadah yang sewenang-wenang. Saya berakhir dengan solusi ini. Ini mirip dengan solusi yang diterima yang menggunakan dorongan (dan juga menghasilkan perilaku yang tidak ditentukan jika panjang wadah tidak sama)
sumber
operator*
untukseq::iterator
mengembalikanstd::tuple
referensi konstanta.Jika Anda memiliki kompilator yang mendukung C ++ 14 (misalnya gcc5), Anda dapat menggunakan yang
zip
disediakan dicppitertools
perpustakaan oleh Ryan Haining, yang terlihat sangat menjanjikan:sumber
Boost.Iterator
zip_iterator
dapat Anda gunakan (contoh ada di dokumen). Ini tidak akan berfungsi dengan range for, tetapi Anda dapat menggunakanstd::for_each
dan lambda.sumber
for_each
akan lebih mudah.std::for_each(make_zip_iterator(make_tuple(Y1.begin(), Y2.begin())), make_zip_iterator(make_tuple(Y1.end(), Y2.end())), [](const tuple<int, int>& t){printf("%d %d\n", get<0>(t), get<1>(t)); });
?Ini adalah versi sederhana yang tidak membutuhkan dorongan. Ini tidak akan sangat efisien karena membuat nilai sementara, dan tidak menggeneralisasi container selain daftar, tetapi tidak memiliki dependensi dan menyelesaikan kasus paling umum untuk pembuatan zip.
Meskipun versi lain lebih fleksibel, seringkali tujuan penggunaan operator daftar adalah membuat satu baris sederhana. Versi ini memiliki kelebihan karena kasus umumnya sederhana.
sumber