How to retrieve all keys (or values) from a std::map and put them into a vector?

C++DictionaryStlStdmap

C++ Problem Overview


This is one of the possible ways I come out:

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

Of course, we can also retrieve all values from the map by defining another functor RetrieveValues.

Is there any other way to achieve this easily? (I'm always wondering why std::map does not include a member function for us to do so.)

C++ Solutions


Solution 1 - C++

While your solution should work, it can be difficult to read depending on the skill level of your fellow programmers. Additionally, it moves functionality away from the call site. Which can make maintenance a little more difficult.

I'm not sure if your goal is to get the keys into a vector or print them to cout so I'm doing both. You may try something like this:

std::map<int, int> m;
std::vector<int> key, value;
for(std::map<int,int>::iterator it = m.begin(); it != m.end(); ++it) {
  key.push_back(it->first);
  value.push_back(it->second);
  std::cout << "Key: " << it->first << std::endl();
  std::cout << "Value: " << it->second << std::endl();
}

Or even simpler, if you are using 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";
}

Personally, I like the BOOST_FOREACH version because there is less typing and it is very explicit about what it is doing.

Solution 2 - C++

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

Solution 3 - C++

There is a boost range adaptor for this purpose:

#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
vector<int> keys;
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));

There is a similar map_values range adaptor for extracting the values.

Solution 4 - C++

C++0x has given us a further, excellent solution:

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

Solution 5 - C++

Based on @rusty-parks solution, but in c++17:

std::map<int, int> items;
std::vector<int> itemKeys;

for (const auto& [key, _] : items) {
    itemKeys.push_back(key);
}

Solution 6 - C++

Yet Another Way using C++20

The ranges library has a keys view, which retrieves the first element in a pair/tuple-like type:

#include <ranges>

auto kv = std::views::keys(m);
std::vector<int> keys{ kv.begin(), kv.end() };

Two related views worth mentioning:

  1. values - to get the values in a map (2nd element in a pair/tuple-like type)
  2. elements - to get the nth elements in a tuple-like type

Solution 7 - C++

@DanDan's answer, using C++11 is:

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

and using C++14 (as noted by @ivan.ukr) we can replace decltype(map_in)::value_type with auto.

Solution 8 - C++

Your solution is fine but you can use an iterator to do it:

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
}

Solution 9 - C++

The SGI STL has an extension called select1st. Too bad it's not in standard STL!

Solution 10 - C++

I think the BOOST_FOREACH presented above is nice and clean, however, there is another option using BOOST as well.

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

Personally, I don't think this approach is as clean as the BOOST_FOREACH approach in this case, but boost::lambda can be really clean in other cases.

Solution 11 - C++

Bit of a c++11 take:

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

Solution 12 - C++

Here's a nice function template using C++11 magic, working for both 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;
}

Check it out here: http://ideone.com/lYBzpL

Solution 13 - C++

Also, if you have Boost, use transform_iterator to avoid making a temporary copy of the keys.

Solution 14 - C++

You can use the versatile boost::transform_iterator. The transform_iterator allows you to transform the iterated values, for example in our case when you want to deal only with the keys, not the values. See http://www.boost.org/doc/libs/1_36_0/libs/iterator/doc/transform_iterator.html#example

Solution 15 - C++

With the structured binding (“destructuring”) declaration syntax of C++17,

you can do this, which is easier to understand.

// To get the keys
std::map<int, double> map;
std::vector<int> keys;
keys.reserve(map.size());
for(const auto& [key, value] : map) {
	keys.push_back(key);
}
// To get the values
std::map<int, double> map;
std::vector<double> values;
values.reserve(map.size());
for(const auto& [key, value] : map) {
	values.push_back(value);
}

Solution 16 - C++

The best non-sgi, non-boost STL solution is to extend map::iterator like so:

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

and then use them like so:

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

Solution 17 - C++

I found the following three lines of code as the easiest way:

// save keys in vector

vector<string> keys;
for (auto & it : m) {
    keys.push_back(it.first);
}

It is a shorten version of the first way of this answer.

Solution 18 - C++

The following functor retrieves the key set of a map:

#include <vector>
#include <iterator>
#include <algorithm>

template <class _Map>
std::vector<typename _Map::key_type> keyset(const _Map& map)
{
    std::vector<typename _Map::key_type> result;
    result.reserve(map.size());
    std::transform(map.cbegin(), map.cend(), std::back_inserter(result), [](typename _Map::const_reference kvpair) {
        return kvpair.first;
    });
    return result;
}

Bonus: The following functors retrieve the value set of a map:

#include <vector>
#include <iterator>
#include <algorithm>
#include <functional>

template <class _Map>
std::vector<typename _Map::mapped_type> valueset(const _Map& map)
{
    std::vector<typename _Map::mapped_type> result;
    result.reserve(map.size());
    std::transform(map.cbegin(), map.cend(), std::back_inserter(result), [](typename _Map::const_reference kvpair) {
        return kvpair.second;
    });
    return result;
}

template <class _Map>
std::vector<std::reference_wrapper<typename _Map::mapped_type>> valueset(_Map& map)
{
    std::vector<std::reference_wrapper<typename _Map::mapped_type>> result;
    result.reserve(map.size());
    std::transform(map.begin(), map.end(), std::back_inserter(result), [](typename _Map::reference kvpair) {
        return std::ref(kvpair.second);
    });
    return result;
}

Usage:

int main()
{
    std::map<int, double> map{
        {1, 9.0},
        {2, 9.9},
        {3, 9.99},
        {4, 9.999},
    };
    auto ks = keyset(map);
    auto vs = valueset(map);
    for (auto& k : ks) std::cout << k << '\n';
    std::cout << "------------------\n";
    for (auto& v : vs) std::cout << v << '\n';
    for (auto& v : vs) v += 100.0;
    std::cout << "------------------\n";
    for (auto& v : vs) std::cout << v << '\n';
    std::cout << "------------------\n";
    for (auto& [k, v] : map) std::cout << v << '\n';

    return 0;
}

Expected output:

1
2
3
4
------------------
9
9.9
9.99
9.999
------------------
109
109.9
109.99
109.999
------------------
109
109.9
109.99
109.999

Solution 19 - C++

With atomic map example

#include <iostream>
#include <map>
#include <vector> 
#include <atomic>

using namespace std;

typedef std::atomic<std::uint32_t> atomic_uint32_t;
typedef std::map<int, atomic_uint32_t> atomic_map_t;

int main()
{
    atomic_map_t m;
    
    m[4] = 456;
    m[2] = 45678;
    
    vector<int> v;
    for(map<int,atomic_uint32_t>::iterator it = m.begin(); it != m.end(); ++it) {
      v.push_back(it->second);
      cout << it->first << " "<<it->second<<"\n";
    }

    return 0;
}

Solution 20 - C++

You can use get_map_keys() from fplus library:

#include<fplus/maps.hpp>
// ...

int main() {
    map<string, int32_t> myMap{{"a", 1}, {"b", 2}};
    vector<string> keys = fplus::get_map_keys(myMap);
    // ...
    return 0;
}

Solution 21 - C++

Slightly similar to one of examples here, simplified from std::map usage perspective.

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

Use like this:

auto keys = getKeys(yourMap);

Solution 22 - C++

> (I'm always wondering why std::map does not include a member function for us to do so.)

Because it can't do it any better than you can do it. If a method's implementation will be no superior to a free function's implementation then in general you should not write a method; you should write a free function.

It's also not immediately clear why it's useful anyway.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOwenView Question on Stackoverflow
Solution 1 - C++Jere.JonesView Answer on Stackoverflow
Solution 2 - C++JuanView Answer on Stackoverflow
Solution 3 - C++AlastairView Answer on Stackoverflow
Solution 4 - C++DanDanView Answer on Stackoverflow
Solution 5 - C++MadiyarView Answer on Stackoverflow
Solution 6 - C++Mercury DimeView Answer on Stackoverflow
Solution 7 - C++James HirschornView Answer on Stackoverflow
Solution 8 - C++Brian R. BondyView Answer on Stackoverflow
Solution 9 - C++Chris Jester-YoungView Answer on Stackoverflow
Solution 10 - C++paxos1977View Answer on Stackoverflow
Solution 11 - C++Rusty ParksView Answer on Stackoverflow
Solution 12 - C++Clemens SielaffView Answer on Stackoverflow
Solution 13 - C++Marcelo CantosView Answer on Stackoverflow
Solution 14 - C++amit kumarView Answer on Stackoverflow
Solution 15 - C++Константин ВанView Answer on Stackoverflow
Solution 16 - C++MariusView Answer on Stackoverflow
Solution 17 - C++ChrissiView Answer on Stackoverflow
Solution 18 - C++KaiserKatzeView Answer on Stackoverflow
Solution 19 - C++Deniz BabatView Answer on Stackoverflow
Solution 20 - C++uol3cView Answer on Stackoverflow
Solution 21 - C++TarmoPikaroView Answer on Stackoverflow
Solution 22 - C++DrPizzaView Answer on Stackoverflow