Copie valores de mapa a vector en STL

Trabajando a través de Effective STL en este momento. El ítem 5 sugiere que, por lo general, es preferible usar funciones de miembros de rango para sus contrapartidas de elemento único. Actualmente deseo copiar todos los valores en un mapa (es decir, no necesito las claves) a un vector.

¿Cuál es la forma más limpia de hacer esto?

Aquí no se puede usar fácilmente un rango porque el iterador que se obtiene de un mapa se refiere a std :: pair, donde los iteradores que se usarían para insertar en un vector se refieren a un objeto del tipo almacenado en el vector, que es (si está descartando la clave) no es un par.

Realmente no creo que sea mucho más limpio que lo obvio:

#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 probablemente volvería a escribir como una función de plantilla si fuera a usarlo más de una vez. Algo como:

 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 ); } } 

Probablemente std::transform usar std::transform para ese propósito. Tal vez prefiera la versión de Neils, dependiendo de lo que sea más legible.


Ejemplo por xtofl (ver comentarios):

 #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) ); } 

Muy genérico, recuerde darle crédito si lo encuentra útil.

Si está utilizando las bibliotecas de impulso , puede usar boost :: bind para acceder al segundo valor del par de la siguiente manera:

 #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) ); } 

Esta solución se basa en una publicación de Michael Goldshteyn en la lista de correo de impulso .

Usando lambdas uno puede realizar lo siguiente:

 { 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); }); } 

Pregunta anterior, nueva respuesta. Con C ++ 11 tenemos el nuevo y sofisticado bucle:

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

donde schemas es un std::map y names es un std::vector .

Esto rellena la matriz (nombres) con claves del mapa (esquemas); cambie s.first a s.second para obtener una matriz de valores.

 #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;} ); 

Lamento no haber agregado ninguna explicación. Creo que el código es tan simple que no requiere ninguna explicación. Asi que:

 transform( beginInputRange, endInputRange, outputIterator, unaryOperation) 

esta función llama a unaryOperation en cada elemento del rango beginInputRange ( beginInputRangeendInputRange ). El valor de la operación se almacena en outputIterator .

Si queremos operar a través de un mapa completo, usamos map.begin () y map.end () como nuestro rango de entrada. Queremos almacenar nuestros valores de mapa en vector, por lo que tenemos que usar back_inserter en nuestro vector: back_inserter(your_values_vector) . El back_inserter es un outputIterator especial que empuja los nuevos elementos al final de la colección dada (como parámetro). El último parámetro es unaryOperation – toma solo un parámetro – inputIterator’s value. Entonces podemos usar lambda: [](auto &kv) { [...] } , donde & kv es solo una referencia al par del elemento del mapa. Entonces, si queremos devolver solo los valores de los elementos del mapa, simplemente podemos devolver kv.second:

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

Creo que esto explica cualquier duda.

Esto es lo que haría.
También usaría una función de plantilla para facilitar la construcción de select2nd.

 #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) ); } 

Pensé que debería ser

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

Una forma es usar functor:

  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); } 

Por qué no:

 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; } 

uso:

auto vec = MapValuesAsVector (anymap);

Sorprendido, nadie ha mencionado la solución más obvia , use el constructor std :: vector.

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