C’est l’une des façons possibles pour moi de sortir:
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"));
Bien sûr, nous pouvons aussi récupérer toutes les valeurs de la carte en définissant un autre foncteur RetrieveValues.
Y a-t-il un autre moyen d'y parvenir facilement? (Je me demande toujours pourquoi std :: map n'inclut pas de fonction membre pour le faire.)
Bien que votre solution doive fonctionner, il peut être difficile à lire en fonction du niveau de compétence de vos collègues programmeurs. De plus, il éloigne les fonctionnalités du site d’appel. Ce qui peut rendre la maintenance un peu plus difficile.
Je ne suis pas sûr que votre objectif soit d'obtenir les clés dans un vecteur ou de les imprimer au cout afin que je fasse les deux. Vous pouvez essayer quelque chose comme ça:
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";
}
Ou encore plus simple, si vous utilisez 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";
}
Personnellement, j'aime bien la version de BOOST_FOREACH car il y a moins de frappe et c'est très explicite à propos de ce qu'il fait.
//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);
Il existe un adaptateur de plage amplifiée à cette fin:
vector<int> keys;
// Retrieve all keys
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));
Il existe un adaptateur de plage map_values similaire pour extraire les valeurs.
C++ 0x nous a donné une excellente solution supplémentaire:
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;});
La réponse de @DanDan, en utilisant C++ 11, est la suivante:
using namespace std;
vector<int> keys;
transform(begin(map_in), end(map_in), back_inserter(keys),
[](decltype(map_in)::value_type const& pair) {
return pair.first;
});
et en utilisant C++ 14 (comme indiqué par @ ivan.ukr), nous pouvons remplacer decltype(map_in)::value_type
par auto
.
Le STL SGI a une extension appelée select1st
. Dommage que ce ne soit pas en standard STL!
Je pense que le BOOST_FOREACH présenté ci-dessus est agréable et propre. Cependant, il existe une autre option utilisant 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") );
Personnellement, je ne pense pas que cette approche soit aussi propre que l'approche BOOST_FOREACH dans ce cas, mais boost :: lambda peut être vraiment propre dans les autres cas.
Votre solution est correcte mais vous pouvez utiliser un itérateur pour le faire:
std::map<int, int> m;
m.insert(std::pair<int, int>(3, 4));
m.insert(std::pair<int, int>(5, 6));
for(std::map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
int key = it->first;
int value = it->second;
//Do something
}
De plus, si vous avez Boost, utilisez transform_iterator pour éviter de créer une copie temporaire des clés.
Un peu de c ++ 11 prend:
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;
}
Vous pouvez utiliser le boost :: transform_iterator polyvalent. Transform_iterator vous permet de transformer les valeurs itérées, par exemple dans notre cas lorsque vous souhaitez traiter uniquement les clés, pas les valeurs. Voir http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example
Voici un modèle de fonction Nice utilisant la magie C++ 11, fonctionnant à la fois pour std :: map, std :: unordered_map:
template<template <typename...> class MAP, class KEY, class VALUE>
std::vector<KEY>
keys(const MAP<KEY, VALUE>& map)
{
std::vector<KEY> result;
result.reserve(map.size());
for(const auto& it : map){
result.emplace_back(it.first);
}
return result;
}
Vérifiez-le ici: http://ideone.com/lYBzpL
La meilleure solution STL non-sgi, non-boost consiste à étendre map :: iterator comme ceci:
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());
}
et ensuite les utiliser comme ceci:
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];
Légèrement similaire à l'un des exemples ici, simplifié à partir de std::map
perspective d'utilisation.
template<class KEY, class VALUE>
std::vector<KEY> getKeys(const std::map<KEY, VALUE>& map)
{
std::vector<KEY> keys(map.size());
for (const auto& it : map)
keys.Push_back(it.first);
return keys;
}
Utilisez comme ceci:
auto keys = getKeys(yourMap);
Basé sur la solution @ rusty-parks, mais en c ++ 17:
std::map<uint32_t, uint32_t> items;
std::vector<uint32_t> itemKeys;
for (auto const& [key, std:ignore] : items) {
itemKeys.emplace_back(key);
}