web-dev-qa-db-fra.com

Obtention de la liste des clés et des valeurs de unordered_map

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.

51
Faheem Mitha

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.

59
Keith Layne

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.

11
Marius Renn

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.

2
Louis

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);
0
elimad