Apakah ada cara untuk mengulang kunci, bukan pasangan peta C ++?
Apakah ada cara untuk mengulang kunci, bukan pasangan peta C ++?
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 :-)]
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.
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.
#include <iostream>
#include <map>
int main()
{
std::map<std::string, int> myMap;
myMap["one"] = 1;
myMap["two"] = 2;
myMap["three"] = 3;
for ( const auto &myPair : myMap ) {
std::cout << myPair.first << "\n";
}
}
Anda dapat melakukan ini hanya dengan memperluas iterator STL untuk peta itu. Misalnya, pemetaan string ke int:
#include <map>
typedef map<string, int> ScoreMap;
typedef ScoreMap::iterator ScoreMapIterator;
class key_iterator : public ScoreMapIterator
{
public:
key_iterator() : ScoreMapIterator() {};
key_iterator(ScoreMapIterator s) : ScoreMapIterator(s) {};
string* operator->() { return (string* const)&(ScoreMapIterator::operator->()->first); }
string operator*() { return ScoreMapIterator::operator*().first; }
};
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()
dan end()
.
ScoreMap m;
m["jim"] = 1000;
m["sally"] = 2000;
for (key_iterator s = m.begin(); s != m.end(); ++s)
printf("\n key %s", s->c_str());
template<typename C> class key_iterator : public C::iterator
, dll
Dengan C ++ 17 Anda dapat menggunakan pengikatan terstruktur di dalam loop for berbasis rentang (menyesuaikan jawaban John H. ):
#include <iostream>
#include <map>
int main() {
std::map<std::string, int> myMap;
myMap["one"] = 1;
myMap["two"] = 2;
myMap["three"] = 3;
for ( const auto &[key, value]: myMap ) {
std::cout << key << '\n';
}
}
Sayangnya, standar C ++ 17 mengharuskan Anda untuk mendeklarasikan value
variabel, meskipun Anda tidak menggunakannya ( std::ignore
karena yang akan digunakan untuk std::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.
for ([[maybe_unused]] const auto &[key, v_not_used] : my_map) { use(key); }
Di bawah solusi template yang lebih umum yang dirujuk Ian ...
#include <map>
template<typename Key, typename Value>
using Map = std::map<Key, Value>;
template<typename Key, typename Value>
using MapIterator = typename Map<Key, Value>::iterator;
template<typename Key, typename Value>
class MapKeyIterator : public MapIterator<Key, Value> {
public:
MapKeyIterator ( ) : MapIterator<Key, Value> ( ) { };
MapKeyIterator ( MapIterator<Key, Value> it_ ) : MapIterator<Key, Value> ( it_ ) { };
Key *operator -> ( ) { return ( Key * const ) &( MapIterator<Key, Value>::operator -> ( )->first ); }
Key operator * ( ) { return MapIterator<Key, Value>::operator * ( ).first; }
};
template<typename Key, typename Value>
class MapValueIterator : public MapIterator<Key, Value> {
public:
MapValueIterator ( ) : MapIterator<Key, Value> ( ) { };
MapValueIterator ( MapIterator<Key, Value> it_ ) : MapIterator<Key, Value> ( it_ ) { };
Value *operator -> ( ) { return ( Value * const ) &( MapIterator<Key, Value>::operator -> ( )->second ); }
Value operator * ( ) { return MapIterator<Key, Value>::operator * ( ).second; }
};
Semua kredit diberikan kepada Ian ... Terima kasih Ian.
Berikut adalah contoh cara melakukannya menggunakan Boost's transform_iterator
#include <iostream>
#include <map>
#include <iterator>
#include "boost/iterator/transform_iterator.hpp"
using std::map;
typedef std::string Key;
typedef std::string Val;
map<Key,Val>::key_type get_key(map<Key,Val>::value_type aPair) {
return aPair.first;
}
typedef map<Key,Val>::key_type (*get_key_t)(map<Key,Val>::value_type);
typedef map<Key,Val>::iterator map_iterator;
typedef boost::transform_iterator<get_key_t, map_iterator> mapkey_iterator;
int main() {
map<Key,Val> m;
m["a"]="A";
m["b"]="B";
m["c"]="C";
// iterate over the map's (key,val) pairs as usual
for(map_iterator i = m.begin(); i != m.end(); i++) {
std::cout << i->first << " " << i->second << std::endl;
}
// iterate over the keys using the transformed iterators
mapkey_iterator keybegin(m.begin(), get_key);
mapkey_iterator keyend(m.end(), get_key);
for(mapkey_iterator i = keybegin; i != keyend; i++) {
std::cout << *i << std::endl;
}
}
Ketika tidak ada eksplisit begin
dan end
diperlukan, 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;
Anda ingin melakukan ini?
std::map<type,type>::iterator iter = myMap.begin();
std::map<type,type>::iterator iter = myMap.end();
for(; iter != endIter; ++iter)
{
type key = iter->first;
.....
}
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.
Jawaban ini seperti jawaban rodrigob kecuali tanpa BOOST_FOREACH
. Anda dapat menggunakan c ++ sebagai gantinya.
#include <map>
#include <boost/range/adaptor/map.hpp>
#include <iostream>
template <typename K, typename V>
void printKeys(std::map<K,V> map){
for(auto key : map | boost::adaptors::map_keys){
std::cout << key << std::endl;
}
}
Tanpa Boost, Anda dapat melakukannya seperti ini. Alangkah baiknya jika Anda bisa menulis operator cast daripada getKeyIterator (), tetapi saya tidak bisa membuatnya untuk dikompilasi.
#include <map>
#include <unordered_map>
template<typename K, typename V>
class key_iterator: public std::unordered_map<K,V>::iterator {
public:
const K &operator*() const {
return std::unordered_map<K,V>::iterator::operator*().first;
}
const K *operator->() const {
return &(**this);
}
};
template<typename K,typename V>
key_iterator<K,V> getKeyIterator(typename std::unordered_map<K,V>::iterator &it) {
return *static_cast<key_iterator<K,V> *>(&it);
}
int _tmain(int argc, _TCHAR* argv[])
{
std::unordered_map<std::string, std::string> myMap;
myMap["one"]="A";
myMap["two"]="B";
myMap["three"]="C";
key_iterator<std::string, std::string> &it=getKeyIterator<std::string,std::string>(myMap.begin());
for (; it!=myMap.end(); ++it) {
printf("%s\n",it->c_str());
}
}
Untuk anak cucu, dan karena saya mencoba menemukan cara untuk membuat rentang, alternatifnya adalah menggunakan boost :: adapters :: transform
Berikut contoh kecilnya:
#include <boost/range/adaptor/transformed.hpp>
#include <iostream>
#include <map>
int main(int argc, const char* argv[])
{
std::map<int, int> m;
m[0] = 1;
m[2] = 3;
m[42] = 0;
auto key_range =
boost::adaptors::transform(
m,
[](std::map<int, int>::value_type const& t)
{ return t.first; }
);
for (auto&& key : key_range)
std::cout << key << ' ';
std::cout << '\n';
return 0;
}
Jika Anda ingin mengulang nilai, gunakan t.second
di lambda.
Banyak jawaban bagus di sini, di bawah ini adalah pendekatan menggunakan beberapa di antaranya yang memungkinkan Anda menulis ini:
void main()
{
std::map<std::string, int> m { {"jim", 1000}, {"sally", 2000} };
for (auto key : MapKeys(m))
std::cout << key << std::endl;
}
Jika itu yang selalu Anda inginkan, berikut adalah kode untuk MapKeys ():
template <class MapType>
class MapKeyIterator {
public:
class iterator {
public:
iterator(typename MapType::iterator it) : it(it) {}
iterator operator++() { return ++it; }
bool operator!=(const iterator & other) { return it != other.it; }
typename MapType::key_type operator*() const { return it->first; } // Return key part of map
private:
typename MapType::iterator it;
};
private:
MapType& map;
public:
MapKeyIterator(MapType& m) : map(m) {}
iterator begin() { return iterator(map.begin()); }
iterator end() { return iterator(map.end()); }
};
template <class MapType>
MapKeyIterator<MapType> MapKeys(MapType& m)
{
return MapKeyIterator<MapType>(m);
}
Saya telah mengadopsi jawaban Ian untuk bekerja dengan semua tipe peta dan tetap mengembalikan referensi untuk operator*
template<typename T>
class MapKeyIterator : public T
{
public:
MapKeyIterator() : T() {}
MapKeyIterator(T iter) : T(iter) {}
auto* operator->()
{
return &(T::operator->()->first);
}
auto& operator*()
{
return T::operator*().first;
}
};
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 ..
std::vector<std::string> vName;
std::vector<int> vNameCount;
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