Quel est le moyen le plus efficace d'obtenir des listes (sous la forme d'un vector
) des clés et des valeurs d'un unordered_map
?
Pour être concret, supposons que la carte en question soit un unordered_map<string, double>
. Je voudrais ensuite obtenir les clés en tant que vector<string>
, et les valeurs sous forme de vector<double>
.
unordered_map<string, double> um;
vector<string> vs = um.enum_keys();
vector<double> vd = um.enum_values();
Je peux simplement parcourir la carte et collecter le résultat, mais existe-t-il une méthode plus efficace? Ce serait bien d'avoir une méthode qui fonctionne également pour une carte régulière, car je pourrais passer à cela.
D'accord, c'est parti:
std::vector<Key> keys;
keys.reserve(map.size());
std::vector<Val> vals;
vals.reserve(map.size());
for(auto kv : map) {
keys.Push_back(kv.first);
vals.Push_back(kv.second);
}
L'efficacité peut probablement être améliorée, mais elle est là. Vous travaillez sur deux conteneurs, donc il n'y a pas vraiment de magie STL qui puisse cacher ce fait.
Comme Louis l'a dit, cela fonctionnera pour n'importe quel conteneur STL map
ou set
.
En utilisant C++ - 14, vous pouvez également effectuer les opérations suivantes (modifiées pour contenir la source complète):
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
typedef string Key;
typedef int Value;
auto key_selector = [](auto pair){return pair.first;};
auto value_selector = [](auto pair){return pair.second;};
int main(int argc, char** argv) {
// Create a test map
unordered_map<Key, Value> map;
map["Eight"] = 8;
map["Ten"] = 10;
map["Eleven"] = 11;
// Vectors to hold keys and values
vector<Key> keys(map.size());
vector<Value> values(map.size());
// This is the crucial bit: Transform map to list of keys (or values)
transform(map.begin(), map.end(), keys.begin(), key_selector);
transform(map.begin(), map.end(), values.begin(), value_selector);
// Make sure this worked: Print out vectors
for (Key key : keys) cout << "Key: " << key << endl;
for (Value value : values) cout << "Value: " << value << endl;
return 0;
}
J'ai compilé cela avec la commande suivante:
g++ keyval.cpp -std=c++14 -o keyval
Le tester a imprimé les clés et les valeurs comme prévu.
En STL, il n'y a pas de méthode intégrée pour obtenir toutes les clés ou valeurs d'une carte.
Il n'y a pas de différence pour itérer une carte non ordonnée ou une carte régulière, la meilleure façon est de l'itérer et de collecter la clé ou la valeur d'un vecteur.
Vous pouvez écrire une fonction de modèle pour itérer tout type de carte.
Rejoindre tard, mais j'ai pensé que cela pourrait être utile à quelqu'un.
Deux fonctions de modèle utilisant key_type
et mapped_type
.
namespace mapExt
{
template<typename myMap>
std::vector<typename myMap::key_type> Keys(const myMap& m)
{
std::vector<typename myMap::key_type> r;
r.reserve(m.size());
for (const auto&kvp : m)
{
r.Push_back(kvp.first);
}
return r;
}
template<typename myMap>
std::vector<typename myMap::mapped_type> Values(const myMap& m)
{
std::vector<typename myMap::mapped_type> r;
r.reserve(m.size());
for (const auto&kvp : m)
{
r.Push_back(kvp.second);
}
return r;
}
}
Usage:
std::map<long, char> mO;
std::unordered_map<long, char> mU;
// set up the maps
std::vector<long> kO = mapExt::Keys(mO);
std::vector<long> kU = mapExt::Keys(mU);
std::vector<char> vO = mapExt::Values(mO);
std::vector<char> vU = mapExt::Values(mU);