Copier les valeurs de la carte sur le vecteur STL

Travailler à travers STL efficace pour le moment. L’élément 5 suggère qu’il est généralement préférable d’utiliser les fonctions des membres de la plage pour leurs homologues à un seul élément. Je souhaite actuellement copier toutes les valeurs d’une carte (c.-à-d. Je n’ai pas besoin des clés) dans un vecteur.

Quelle est la manière la plus propre de le faire?

Vous ne pouvez pas utiliser facilement une plage ici car l’iterator que vous obtenez d’une carte fait référence à une paire std ::, où les iterators que vous utiliseriez pour insérer dans un vecteur font référence à un object du type stocké dans le vecteur, qui est (si vous enlevez la clé) pas une paire.

Je ne pense vraiment pas que cela devient beaucoup plus propre que l’évidence:

#include  #include  #include  using namespace std; int main() { typedef map  MapType; MapType m; vector  v; // populate map somehow for( MapType::iterator it = m.begin(); it != m.end(); ++it ) { v.push_back( it->second ); } } 

que je réécrirais probablement comme une fonction de modèle si je devais l’utiliser plus d’une fois. Quelque chose comme:

 template  void MapToVec( const M & m, V & v ) { for( typename M::const_iterator it = m.begin(); it != m.end(); ++it ) { v.push_back( it->second ); } } 

Vous pourriez probablement utiliser std::transform à cette fin. Je préférerais peut-être la version de Neils, selon ce qui est plus lisible.


Exemple par xtofl (voir commentaires):

 #include  #include  #include  #include  template< typename tPair > struct second_t { typename tPair::second_type operator()( const tPair& p ) const { return p.second; } }; template< typename tMap > second_t< typename tMap::value_type > second( const tMap& m ) { return second_t< typename tMap::value_type >(); } int main() { std::map m; m[0]=true; m[1]=false; //... std::vector v; std::transform( m.begin(), m.end(), std::back_inserter( v ), second(m) ); std::transform( m.begin(), m.end(), std::ostream_iterator( std::cout, ";" ), second(m) ); } 

Très générique, n’oubliez pas de lui donner crédit si vous le trouvez utile.

Si vous utilisez les bibliothèques de boost , vous pouvez utiliser boost :: bind pour accéder à la deuxième valeur de la paire comme suit:

 #include  #include  #include  #include  #include  int main() { typedef std::map MapT; typedef std::vector VecT; MapT map; VecT vec; map["one"] = 1; map["two"] = 2; map["three"] = 3; map["four"] = 4; map["five"] = 5; std::transform( map.begin(), map.end(), std::back_inserter(vec), boost::bind(&MapT::value_type::second,_1) ); } 

Cette solution est basée sur un post de Michael Goldshteyn sur la liste de diffusion boost .

En utilisant lambdas, on peut effectuer les opérations suivantes:

 { std::map m; std::vector v; v.reserve(m.size()); std::for_each(m.begin(),m.end(), [&v](const std::map::value_type& p) { v.push_back(p.second); }); } 

Ancienne question, nouvelle réponse. Avec C ++ 11, nous avons la nouvelle fantaisie pour la boucle:

 for (const auto &s : schemas) names.push_back(s.first); 

où schemas est un std::map et names est un std::vector .

Cela remplit le tableau (noms) avec les clés de la carte (schémas); changez d’ s.first de s.second pour obtenir un tableau de valeurs.

 #include  // std::transform #include  // std::back_inserter std::transform( your_map.begin(), your_map.end(), std::back_inserter(your_values_vector), [](auto &kv){ return kv.second;} ); 

Désolé que je n’ai pas ajouté d’explication – Je pensais que le code est si simple qu’il ne nécessite aucune explication. Alors:

 transform( beginInputRange, endInputRange, outputIterator, unaryOperation) 

cette fonction appelle unaryOperation sur chaque élément de la plage beginInputRange ( beginInputRangeendInputRange ). La valeur de l’opération est stockée dans outputIterator .

Si nous voulons opérer à travers une carte entière, nous utilisons map.begin () et map.end () comme notre plage d’entrée. Nous voulons stocker nos valeurs de carte dans vector – nous devons donc utiliser back_inserter sur notre vecteur: back_inserter(your_values_vector) . Le back_inserter est un outputIterator spécial qui pousse de nouveaux éléments à la fin d’une collection donnée (en tant que paramètre). Le dernier paramètre est unaryOperation – il ne prend qu’un seul paramètre – la valeur de inputIterator. Nous pouvons donc utiliser lambda: [](auto &kv) { [...] } , où & kv n’est qu’une référence à la paire d’éléments. Donc, si nous voulons renvoyer uniquement les valeurs des éléments de map, nous pouvons simplement retourner kv.second:

 [](auto &kv) { return kv.second; } 

Je pense que cela explique tout doute.

Voici ce que je ferais.
Aussi, je voudrais utiliser une fonction de modèle pour rendre la construction de select2nd plus facile.

 #include  #include  #include  #include  #include  /* * A class to extract the second part of a pair */ template struct select2nd { typename T::second_type operator()(T const& value) const {return value.second;} }; /* * A utility template function to make the use of select2nd easy. * Pass a map and it automatically creates a select2nd that utilizes the * value type. This works nicely as the template functions can deduce the * template parameters based on the function parameters. */ template select2nd make_select2nd(T const& m) { return select2nd(); } int main() { std::map m; std::vector v; /* * Please note: You must use std::back_inserter() * As transform assumes the second range is as large as the first. * Alternatively you could pre-populate the vector. * * Use make_select2nd() to make the function look nice. * Alternatively you could use: * select2nd::value_type>() */ std::transform(m.begin(),m.end(), std::back_inserter(v), make_select2nd(m) ); } 

Je pensais que ça devrait être

std :: transform (map.begin (), map.end (), std :: back_inserter (vec), boost :: bind (& MapT :: value_type :: first, _1));

Un moyen est d’utiliser le foncteur:

  template  class CopyMapToVec { public: CopyMapToVec(std::vector& aVec): mVec(aVec){} bool operator () (const std::pair& mapVal) const { mVec.push_back(mapVal.second); return true; } private: std::vector& mVec; }; int main() { std::map myMap; myMap["test1"] = 1; myMap["test2"] = 2; std::vector myVector; //reserve the memory for vector myVector.reserve(myMap.size()); //create the functor CopyMapToVec aConverter(myVector); //call the functor std::for_each(myMap.begin(), myMap.end(), aConverter); } 

Pourquoi pas:

 template std::vector MapValuesAsVector(const std::map& map) { std::vector vec; vec.reserve(map.size()); std::for_each(std::begin(map), std::end(map), [&vec] (const std::map::value_type& entry) { vec.push_back(entry.second); }); return vec; } 

usage:

auto vec = MapValuesAsVector (anymap);

Surpris, personne n’a mentionné la solution la plus évidente , utilisez le constructeur std :: vector.

 template std::vector> mapToVector(const std::unordered_map &map) { return std::vector>(map.begin(), map.end()); }