Ide untuk mendapatkan iterator ke nilai adalah dengan menggunakannya dalam algoritma STL, misalnya, persimpangan kunci dari dua peta. Solusi yang melibatkan Boost tidak memungkinkan ini, karena itu akan menghasilkan iterator Boost. Jawaban terburuk mendapat suara terbanyak!
Jawaban:
70
Jika Anda benar-benar perlu menyembunyikan nilai yang dikembalikan iterator "asli" (misalnya karena Anda ingin menggunakan iterator kunci dengan algoritme standar, sehingga mereka beroperasi pada kunci, bukan berpasangan), lihat Boost's transform_iterator .
[Tip: saat melihat dokumentasi Boost untuk kelas baru, baca "contoh" di bagian akhir terlebih dahulu. Anda kemudian memiliki kesempatan olahraga untuk mencari tahu apa yang sedang dibicarakan oleh semua itu :-)]
map adalah wadah asosiatif. Oleh karena itu, iterator adalah sepasang kunci, val. JIKA Anda hanya membutuhkan kunci, Anda dapat mengabaikan bagian nilai dari pasangan.
for(std::map<Key,Val>::iterator iter = myMap.begin(); iter != myMap.end();++iter){Key k = iter->first;//ignore value//Value v = iter->second;}
EDIT:: Jika Anda hanya ingin mengekspos kunci ke luar maka Anda dapat mengonversi peta ke vektor atau kunci dan mengekspos.
Tapi kemudian akan sangat buruk untuk mengekspos iterator vektor di luar.
Naveen
Jangan buka iterator. Berikan saja kunci dalam vektor
aJ.
5
Anda mungkin ingin melakukan ini sebagai gantinya: const Key& k(iter->first);
strickli
17
Dua hal, ini menjawab pertanyaan OP dengan tepat jawaban yang ia sudah tahu dan tidak mencari, kedua metode ini tidak akan membantu Anda jika Anda ingin melakukan sesuatu seperti: std::vector<Key> v(myMap.begin(), myMap.end()).
Andreas Magnusson
Jangan mengonversi kunci menjadi vektor. Membuat vektor baru mengalahkan tujuan iterasi, yang seharusnya cepat dan tidak mengalokasikan apa pun. Juga, akan lambat untuk set besar.
Kevin Chen
85
Dengan C ++ 11 sintaks iterasinya sederhana. Anda masih mengulang berpasangan, tetapi mengakses kuncinya saja itu mudah.
Sayangnya, standar C ++ 17 mengharuskan Anda untuk mendeklarasikan valuevariabel, meskipun Anda tidak menggunakannya ( std::ignorekarena yang akan digunakan untuk std::tie(..)tidak berfungsi, lihat diskusi ini ).
Oleh karena itu, beberapa kompiler mungkin memperingatkan Anda tentang valuevariabel yang tidak digunakan ! Peringatan waktu kompilasi mengenai variabel yang tidak digunakan adalah larangan untuk kode produksi apa pun dalam pikiran saya. Jadi, ini mungkin tidak berlaku untuk versi kompilator tertentu.
tidak bisakah Anda menetapkannya ke std :: ignore pada prinsipnya? Apakah itu benar-benar merusak efisiensi dalam kode yang dikompilasi atau apakah itu benar-benar tidak menghasilkan apa-apa? (Saya tidak bermaksud dalam mengikat melainkan sebagai tindakan dalam lingkaran)
KotoroShinoto
Sejak C ++ 17 Anda juga dapat menggunakan [[maybe_unused]]. Ini menekan peringatan. Seperti ini:for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
arhuaco
15
Di bawah solusi template yang lebih umum yang dirujuk Ian ...
Ketika tidak ada eksplisit begindan enddiperlukan, yaitu untuk perulangan-rentang, perulangan atas kunci (contoh pertama) atau nilai (contoh kedua) dapat diperoleh dengan
#include<boost/range/adaptors.hpp>
map<Key,Value> m;for(auto k : boost::adaptors::keys(m))
cout << k << endl;for(auto v : boost::adaptors::values(m))
cout << v << endl;
std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();for(; iter != endIter;++iter){
type key = iter->first;.....}
Ya, saya tahu, masalahnya adalah saya memiliki kelas A {publik: // saya ingin mengekspos iterator atas kunci peta pribadi di sini private: map <>};
Bogdan Balan
Dalam hal ini, saya rasa Anda dapat membuat std :: list dengan menggunakan std :: trasnform dan hanya mengambil kunci dari peta. Kemudian Anda dapat mengekspos iterator daftar karena memasukkan lebih banyak elemen ke daftar tidak akan membatalkan iterator yang ada.
Naveen
3
Jika Anda memerlukan iterator yang hanya mengembalikan kunci, Anda perlu menggabungkan iterator peta di kelas Anda sendiri yang menyediakan antarmuka yang diinginkan. Anda dapat mendeklarasikan kelas iterator baru dari awal seperti di sini , menggunakan konstruksi helper yang sudah ada. Jawaban ini menunjukkan cara menggunakan Boost transform_iteratoruntuk menggabungkan iterator yang hanya mengembalikan nilai / kunci.
Tanpa Boost, Anda dapat melakukannya seperti ini. Alangkah baiknya jika Anda bisa menulis operator cast daripada getKeyIterator (), tetapi saya tidak bisa membuatnya untuk dikompilasi.
Saya tahu ini tidak menjawab pertanyaan Anda, tetapi satu opsi yang mungkin ingin Anda lihat hanyalah memiliki dua vektor dengan indeks yang sama menjadi informasi "ditautkan" ..
jika Anda ingin menghitung nama berdasarkan nama Anda cukup melakukan pengulangan cepat untuk vName.size (), dan ketika Anda menemukannya, itulah indeks untuk vNameCount yang Anda cari.
Tentu ini mungkin tidak memberi Anda semua fungsionalitas peta, dan tergantung mungkin atau mungkin tidak lebih baik, tetapi mungkin lebih mudah jika Anda tidak tahu kuncinya, dan tidak perlu menambahkan terlalu banyak pemrosesan.
Ingatlah ketika Anda menambah / menghapus dari satu Anda harus melakukannya dari yang lain atau hal-hal akan menjadi gila heh: P
Jawaban:
Jika Anda benar-benar perlu menyembunyikan nilai yang dikembalikan iterator "asli" (misalnya karena Anda ingin menggunakan iterator kunci dengan algoritme standar, sehingga mereka beroperasi pada kunci, bukan berpasangan), lihat Boost's transform_iterator .
[Tip: saat melihat dokumentasi Boost untuk kelas baru, baca "contoh" di bagian akhir terlebih dahulu. Anda kemudian memiliki kesempatan olahraga untuk mencari tahu apa yang sedang dibicarakan oleh semua itu :-)]
sumber
map adalah wadah asosiatif. Oleh karena itu, iterator adalah sepasang kunci, val. JIKA Anda hanya membutuhkan kunci, Anda dapat mengabaikan bagian nilai dari pasangan.
EDIT:: Jika Anda hanya ingin mengekspos kunci ke luar maka Anda dapat mengonversi peta ke vektor atau kunci dan mengekspos.
sumber
const Key& k(iter->first);
std::vector<Key> v(myMap.begin(), myMap.end())
.Dengan C ++ 11 sintaks iterasinya sederhana. Anda masih mengulang berpasangan, tetapi mengakses kuncinya saja itu mudah.
sumber
Tanpa Boost
Anda dapat melakukan ini hanya dengan memperluas iterator STL untuk peta itu. Misalnya, pemetaan string ke int:
Anda juga dapat melakukan ekstensi ini di template , untuk solusi yang lebih umum.
Anda menggunakan iterator Anda persis seperti Anda akan menggunakan iterator daftar, kecuali Anda melakukan iterasi pada peta
begin()
danend()
.sumber
template<typename C> class key_iterator : public C::iterator
, dllDengan C ++ 17 Anda dapat menggunakan pengikatan terstruktur di dalam loop for berbasis rentang (menyesuaikan jawaban John H. ):
Sayangnya, standar C ++ 17 mengharuskan Anda untuk mendeklarasikan
value
variabel, meskipun Anda tidak menggunakannya (std::ignore
karena yang akan digunakan untukstd::tie(..)
tidak berfungsi, lihat diskusi ini ).Oleh karena itu, beberapa kompiler mungkin memperingatkan Anda tentang
value
variabel yang tidak digunakan ! Peringatan waktu kompilasi mengenai variabel yang tidak digunakan adalah larangan untuk kode produksi apa pun dalam pikiran saya. Jadi, ini mungkin tidak berlaku untuk versi kompilator tertentu.sumber
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
Di bawah solusi template yang lebih umum yang dirujuk Ian ...
Semua kredit diberikan kepada Ian ... Terima kasih Ian.
sumber
Anda mencari map_keys , dengan itu Anda dapat menulis sesuatu seperti
sumber
BOOST_FOREACH(const key_t& key, ...
Berikut adalah contoh cara melakukannya menggunakan Boost's transform_iterator
sumber
Ketika tidak ada eksplisit
begin
danend
diperlukan, yaitu untuk perulangan-rentang, perulangan atas kunci (contoh pertama) atau nilai (contoh kedua) dapat diperoleh dengansumber
Anda ingin melakukan ini?
sumber
Jika Anda memerlukan iterator yang hanya mengembalikan kunci, Anda perlu menggabungkan iterator peta di kelas Anda sendiri yang menyediakan antarmuka yang diinginkan. Anda dapat mendeklarasikan kelas iterator baru dari awal seperti di sini , menggunakan konstruksi helper yang sudah ada. Jawaban ini menunjukkan cara menggunakan Boost
transform_iterator
untuk menggabungkan iterator yang hanya mengembalikan nilai / kunci.sumber
Anda bisa
std::map<K,V>::iterator
std::transform
dari Andamap.begin()
untukmap.end()
denganboost::bind( &pair::second, _1 )
functor->second
anggota tersebut saat melakukan iterasi denganfor
loop.sumber
Jawaban ini seperti jawaban rodrigob kecuali tanpa
BOOST_FOREACH
. Anda dapat menggunakan c ++ sebagai gantinya.sumber
Tanpa Boost, Anda dapat melakukannya seperti ini. Alangkah baiknya jika Anda bisa menulis operator cast daripada getKeyIterator (), tetapi saya tidak bisa membuatnya untuk dikompilasi.
sumber
Untuk anak cucu, dan karena saya mencoba menemukan cara untuk membuat rentang, alternatifnya adalah menggunakan boost :: adapters :: transform
Berikut contoh kecilnya:
Jika Anda ingin mengulang nilai, gunakan
t.second
di lambda.sumber
Banyak jawaban bagus di sini, di bawah ini adalah pendekatan menggunakan beberapa di antaranya yang memungkinkan Anda menulis ini:
Jika itu yang selalu Anda inginkan, berikut adalah kode untuk MapKeys ():
sumber
Saya telah mengadopsi jawaban Ian untuk bekerja dengan semua tipe peta dan tetap mengembalikan referensi untuk
operator*
sumber
Saya tahu ini tidak menjawab pertanyaan Anda, tetapi satu opsi yang mungkin ingin Anda lihat hanyalah memiliki dua vektor dengan indeks yang sama menjadi informasi "ditautkan" ..
Jadi di ..
jika Anda ingin menghitung nama berdasarkan nama Anda cukup melakukan pengulangan cepat untuk vName.size (), dan ketika Anda menemukannya, itulah indeks untuk vNameCount yang Anda cari.
Tentu ini mungkin tidak memberi Anda semua fungsionalitas peta, dan tergantung mungkin atau mungkin tidak lebih baik, tetapi mungkin lebih mudah jika Anda tidak tahu kuncinya, dan tidak perlu menambahkan terlalu banyak pemrosesan.
Ingatlah ketika Anda menambah / menghapus dari satu Anda harus melakukannya dari yang lain atau hal-hal akan menjadi gila heh: P
sumber