c++ - programacion - Copiar valores de mapa a vector en STL
que es un map en c++ (11)
Esto es lo que yo haría.
También usaría una función de plantilla para facilitar la construcción de select2nd.
#include <map>
#include <vector>
#include <algorithm>
#include <memory>
#include <string>
/*
* A class to extract the second part of a pair
*/
template<typename T>
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<typename T>
select2nd<typename T::value_type> make_select2nd(T const& m)
{
return select2nd<typename T::value_type>();
}
int main()
{
std::map<int,std::string> m;
std::vector<std::string> 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<std::map<int,std::string>::value_type>()
*/
std::transform(m.begin(),m.end(),
std::back_inserter(v),
make_select2nd(m)
);
}
Trabajando a través de Effective STL en este momento. El ítem 5 sugiere que generalmente es preferible usar funciones de miembros de rango para sus contrapartes de un solo elemento. 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?
No puede usar fácilmente un rango aquí porque el iterador que obtiene de un mapa se refiere a un std :: pair, donde los iteradores que usaría 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 se ponga mucho más limpio que lo obvio:
#include <map>
#include <vector>
#include <string>
using namespace std;
int main() {
typedef map <string, int> MapType;
MapType m;
vector <int> v;
// populate map somehow
for( MapType::iterator it = m.begin(); it != m.end(); ++it ) {
v.push_back( it->second );
}
}
que probablemente reescribiría como una función de plantilla si fuera a usarla más de una vez. Algo como:
template <typename M, typename V>
void MapToVec( const M & m, V & v ) {
for( typename M::const_iterator it = m.begin(); it != m.end(); ++it ) {
v.push_back( it->second );
}
}
Pensé que debería ser
std :: transform (map.begin (), map.end (), std :: back_inserter (vec), boost :: bind (& MapT :: value_type :: first, _1));
Por qué no:
template<typename K, typename V>
std::vector<V> MapValuesAsVector(const std::map<K, V>& map)
{
std::vector<V> vec;
vec.reserve(map.size());
std::for_each(std::begin(map), std::end(map),
[&vec] (const std::map<K, V>::value_type& entry)
{
vec.push_back(entry.second);
});
return vec;
}
uso:
auto vec = MapValuesAsVector (anymap);
Probablemente podrías usar std::transform
para ese propósito. Tal vez prefiero la versión Neils, dependiendo de lo que sea más legible.
Ejemplo por xtofl (ver comentarios):
#include <map>
#include <vector>
#include <algorithm>
#include <iostream>
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<int,bool> m;
m[0]=true;
m[1]=false;
//...
std::vector<bool> v;
std::transform( m.begin(), m.end(), std::back_inserter( v ), second(m) );
std::transform( m.begin(), m.end(), std::ostream_iterator<bool>( std::cout, ";" ), second(m) );
}
Muy genérico, recuerde darle crédito si lo encuentra útil.
Si está utilizando las bibliotecas boost , puede usar boost :: bind para acceder al segundo valor del par de la siguiente manera:
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
int main()
{
typedef std::map<std::string, int> MapT;
typedef std::vector<int> 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 boost .
Sorprendido, nadie ha mencionado la solución más obvia , use el constructor std :: vector.
template<typename K, typename V>
std::vector<std::pair<K,V>> mapToVector(const std::unordered_map<K,V> &map)
{
return std::vector<std::pair<K,V>>(map.begin(), map.end());
}
Una forma es usar funtor:
template <class T1, class T2>
class CopyMapToVec
{
public:
CopyMapToVec(std::vector<T2>& aVec): mVec(aVec){}
bool operator () (const std::pair<T1,T2>& mapVal) const
{
mVec.push_back(mapVal.second);
return true;
}
private:
std::vector<T2>& mVec;
};
int main()
{
std::map<std::string, int> myMap;
myMap["test1"] = 1;
myMap["test2"] = 2;
std::vector<int> myVector;
//reserve the memory for vector
myVector.reserve(myMap.size());
//create the functor
CopyMapToVec<std::string, int> aConverter(myVector);
//call the functor
std::for_each(myMap.begin(), myMap.end(), aConverter);
}
Usando lambdas se puede realizar lo siguiente:
{
std::map<std::string,int> m;
std::vector<int> v;
v.reserve(m.size());
std::for_each(m.begin(),m.end(),
[&v](const std::map<std::string,int>::value_type& p)
{ v.push_back(p.second); });
}
Vieja pregunta, nueva respuesta. Con C ++ 11 tenemos el nuevo y elegante bucle para:
for (const auto &s : schemas)
names.push_back(s.first);
donde esquemas es un std::map
y nombres es un std::vector
.
Esto llena la matriz (nombres) con claves del mapa (esquemas); cambie de s.first
a s.second
para obtener una matriz de valores.
#include <algorithm> // std::transform
#include <iterator> // 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. Pensé que el código es tan simple que no requiere ninguna explicación. Asi que:
transform( beginInputRange, endInputRange, outputIterator, unaryOperation)
esta función llama unaryOperation
en cada elemento del rango beginInputRange
( beginInputRange
- endInputRange
). 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 mapas en vectores, 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 nuevos elementos al final de la colección dada (como parámetro). El último parámetro es unaryOperation: solo toma un parámetro: el valor del inputIterator. 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.