que - setw c++ ejemplo




¿Cómo recuperar todas las claves(o valores) de un std:: map y ponerlas en un vector? (10)

Esta es una de las posibles formas en que salgo:

struct RetrieveKey
{
    template <typename T>
    typename T::first_type operator()(T keyValuePair) const
    {
        return keyValuePair.first;
    }
};

map<int, int> m;
vector<int> keys;

// Retrieve all keys
transform(m.begin(), m.end(), back_inserter(keys), RetrieveKey());

// Dump all keys
copy(keys.begin(), keys.end(), ostream_iterator<int>(cout, "\n"));

Por supuesto, también podemos recuperar todos los valores del mapa definiendo otro functor RetrieveValues .

¿Hay alguna otra forma de lograr esto fácilmente? (Siempre me pregunto por qué std :: map no incluye una función de miembro para que lo hagamos).


(Siempre me pregunto por qué std :: map no incluye una función de miembro para que lo hagamos).

Porque no puede hacerlo mejor de lo que puedes hacerlo. Si la implementación de un método no será superior a la implementación de una función gratuita, entonces, en general, no debe escribir un método; deberías escribir una función gratuita.

Tampoco está claro de inmediato por qué es útil de todos modos.


Además, si tiene Boost, use transform_iterator para evitar hacer una copia temporal de las claves.


C ++ 0x nos ha dado una solución adicional excelente:

std::vector<int> keys;

std::transform(
    m_Inputs.begin(),
    m_Inputs.end(),
    std::back_inserter(keys),
    [](const std::map<int,int>::value_type &pair){return pair.first;});

Creo que el BOOST_FOREACH presentado anteriormente es bueno y limpio, sin embargo, hay otra opción que también usa BOOST.

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

std::map<int, int> m;
std::vector<int> keys;

using namespace boost::lambda;

transform(      m.begin(), 
                m.end(), 
                back_inserter(keys), 
                bind( &std::map<int,int>::value_type::first, _1 ) 
          );

copy( keys.begin(), keys.end(), std::ostream_iterator<int>(std::cout, "\n") );

Personalmente, no creo que este enfoque sea tan limpio como el enfoque BOOST_FOREACH en este caso, pero boost :: lambda puede ser realmente limpio en otros casos.


Hay un adaptador de rango de impulso para este propósito:

vector<int> keys;
// Retrieve all keys
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));

Hay un adaptador de rango map_values ​​similar para extraer los valores.


La mejor solución STL que no es sgi ni boost es extender map :: iterator de la siguiente manera:

template<class map_type>
class key_iterator : public map_type::iterator
{
public:
    typedef typename map_type::iterator map_iterator;
    typedef typename map_iterator::value_type::first_type key_type;

    key_iterator(const map_iterator& other) : map_type::iterator(other) {} ;

    key_type& operator *()
    {
        return map_type::iterator::operator*().first;
    }
};

// helpers to create iterators easier:
template<class map_type>
key_iterator<map_type> key_begin(map_type& m)
{
    return key_iterator<map_type>(m.begin());
}
template<class map_type>
key_iterator<map_type> key_end(map_type& m)
{
    return key_iterator<map_type>(m.end());
}

y luego utilícelos así:

        map<string,int> test;
        test["one"] = 1;
        test["two"] = 2;

        vector<string> keys;

//      // method one
//      key_iterator<map<string,int> > kb(test.begin());
//      key_iterator<map<string,int> > ke(test.end());
//      keys.insert(keys.begin(), kb, ke);

//      // method two
//      keys.insert(keys.begin(),
//           key_iterator<map<string,int> >(test.begin()),
//           key_iterator<map<string,int> >(test.end()));

        // method three (with helpers)
        keys.insert(keys.begin(), key_begin(test), key_end(test));

        string one = keys[0];


Si bien su solución debería funcionar, puede ser difícil de leer dependiendo del nivel de habilidad de sus compañeros programadores. Además, aleja la funcionalidad del sitio de llamadas. Lo cual puede hacer que el mantenimiento sea un poco más difícil.

No estoy seguro de si tu objetivo es poner las llaves en un vector o imprimirlas para que las use, así que estoy haciendo las dos cosas. Puede intentar algo como esto:

map<int, int> m;
vector<int> v;
for(map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
  v.push_back(it->first);
  cout << it->first << "\n";
}

O incluso más simple, si estás usando Boost:

map<int,int> m;
pair<int,int> me; // what a map<int, int> is made of
vector<int> v;
BOOST_FOREACH(me, m) {
  v.push_back(me.first);
  cout << me.first << "\n";
}

Personalmente, me gusta la versión BOOST_FOREACH porque hay menos tipeo y es muy explícito sobre lo que está haciendo.


Un poco de c ++ 11 tomar:

std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto & kvp : items)
{
    itemKeys.emplace_back(kvp.first);
    std::cout << kvp.first << std::endl;
}

//c++0x too
std::map<int,int> mapints;
std::vector<int> vints;
vints.reserve(mapints.size());
for(auto const& imap: mapints)
    vints.push_back(imap.first);




stdmap