343

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.)

thor
  • 21,418
  • 31
  • 87
  • 173
Owen
  • 3,851
  • 2
  • 18
  • 12

24 Answers24

229

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 the Boost library:

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.

JSong
  • 348
  • 3
  • 19
Jere.Jones
  • 9,915
  • 5
  • 35
  • 38
  • 1
    Go figures I'd end up back here after my Google search. Yours is the answer *I* prefer :) – mpen Apr 14 '09 at 20:15
  • 4
    @Jere - Have you actually worked with `BOOST_FOREACH`? The code you propose here is totally wrong – Manuel Mar 05 '10 at 19:25
  • Manuel is correct, the syntax for BOOST_FOREACH iterating over a map is to first define the element type with no commas (ie typedef pair element_type;) then iterate using the actual elements (ie BOOST_FOREACH(element_type& e, m) – Jamie Cook Jul 09 '10 at 09:19
  • 2
    @Jamie - that is another way, but the boost docs show specifying the variable and its type prior to the BOOST_FOREACH if the type contains a comma. They also show typedefing it. So, I'm confused, what is wrong with my code? – Jere.Jones Jul 09 '10 at 16:56
  • @Manuel - sorry, I just saw your response. Can you specify what is wrong? – Jere.Jones Jul 09 '10 at 16:56
  • @Jere.Jones, your code is wrong because your variable is an iterator. The entire point of BOOST_FOREACH is that you don't need iterators, you just get given the elements one after the other. See my previous comment or this code dump http://www.pastie.org/1045222 – Jamie Cook Jul 15 '10 at 06:36
  • 1
    @Manual - OMG, as soon as I read your first sentence I smacked my head. Thanks! I have corrected it so as to not confuse future visitors. – Jere.Jones Jul 19 '10 at 16:51
  • 19
    Curious, wouldn't it make sense to presize the vector to prevent resize allocation? – Alan Oct 16 '13 at 22:34
  • Now when C++11 is available, the method described by Juan below is better in my opinion: //c++0x too std::map mapints; std::vector vints; for(auto imap: mapints) vints.push_back(imap.first); – user561749 Nov 15 '15 at 16:30
  • 5
    Don't forget to do `v.reserve(m.size())` to avoid having the vector resize during the transfer. – Brian White Mar 21 '17 at 14:34
  • 1
    @BrianWhite This is bad advice. Stroustrup recommends to not call reserve (https://www.stroustrup.com/bs_faq2.html). – Étienne Aug 31 '20 at 08:40
  • @Étienne, his observation at that link (not actually a recommendation) is under the context of "the cost of std::vector growing incrementally". In this case, it's moving to a known, fixed size so I think it's only a benefit. – Brian White Sep 02 '20 at 20:09
  • @Brian White you may also make the code slower by calling reserve explicitly, depending on the size of the map. It is a recommendation from Stroustrup to not call it explicitly because this is really a tiny speed optimization with a reasonable implementation of std::vector, he also recommend it in his c++ book "the c++ programming language". – Étienne Sep 02 '20 at 20:17
199
//c++0x too
std::map<int,int> mapints;
std::vector<int> vints;
for(auto const& imap: mapints)
    vints.push_back(imap.first);
Étienne
  • 4,773
  • 2
  • 33
  • 58
Juan
  • 1,991
  • 1
  • 11
  • 2
  • 7
    Nice. Forget about `it = ...begin(); it != ...end`. Nicest would of course be std::map having a method keys() returning that vector... – masterxilo May 18 '13 at 23:28
  • 2
    @BenHymers: It seems to me this answer was given at `answered Mar 13 '12 at 22:33`, which is several months _after_ C++11 became C++. – Sebastian Mach Jul 22 '13 at 14:31
  • 9
    for (auto &imap) is more precise because no copy operation. – ABCD Jun 23 '15 at 06:20
  • 2
    @StudentT, better yet, `for(auto const & imap : mapints)`. – cp.engr Oct 23 '15 at 16:58
  • 2
    I prefer `for (auto&& imap : mapints)`. See http://edmundv.home.xs4all.nl/blog/2014/01/28/use-auto-and-and-for-range-based-for-loops/ – Rotsiser Mho Oct 25 '15 at 04:49
  • 2
    Also, some of us have to work in environments without C++11 support -_- – Daniel Apr 04 '16 at 13:56
  • 1
    If you plan to use this efficiently, you should add `vints.reserve( mapints.size() );` before the loop. – DrPepperJo Feb 13 '17 at 23:53
  • 2
    Person from the future here. Regarding @user283145 's comment, now C++==C++17 and that won't last too long either. I, for one, appreciate when answers specify language compatibility. "C++" is a language that has and will continue to change. – chessofnerd Nov 30 '18 at 17:54
  • @Antonio I rolled-back your edit, calling reserve explicitely is not the recommended way and is a sign of premature optimization in most cases (see https://www.stroustrup.com/bs_faq2.html) – Étienne Aug 31 '20 at 08:46
  • @Étienne I agree it’s a matter of style, although depending on the platform I have seen allocation being more or less costly (in Android it’s more costly in my experience). I see giving any available information to the compiler to optimize as a good practice, in this case being: “the vector will grow at least this big” – Antonio Sep 02 '20 at 16:49
69

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.

Zitrax
  • 19,036
  • 20
  • 88
  • 110
Alastair
  • 4,475
  • 1
  • 26
  • 23
64

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;});
DanDan
  • 10,462
  • 8
  • 53
  • 69
  • 31
    In my view there is nothing excellent about it. std::vector keys; keys.reserve(m_Inputs.size()); for ( auto keyValue : m_Inputs){ keys.push_back(keyValue.first); } Is far better than the cryptic transform. Even in terms of performance. This one is better. – Jagannath Jun 11 '12 at 14:59
  • 5
    You can reserve the size of keys here too if you want comparable performance. use the transform if you want to avoid a for loop. – DanDan Jun 14 '12 at 20:35
  • 4
    just want to add - can use [](const auto& pair) – ivan.ukr Mar 02 '16 at 15:04
  • @ivan.ukr what compiler are you using? This syntax is not allowed here: *'const auto &': a parameter cannot have a type that contains 'auto'* – Gobe Apr 20 '16 at 20:37
  • Visual C++ 2015 Update 1, also works for me with Visual C++2015 Update 2 – ivan.ukr Apr 26 '16 at 00:22
  • 4
    @ivan.ukr auto parameter in lambda is c++14 – roalz Oct 13 '17 at 21:24
  • @Jagannath How's your version more performant if this one also has a `keys.reserve()`? Just curious. – legends2k May 26 '20 at 07:57
64

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
Mercury Dime
  • 1,141
  • 2
  • 10
  • 10
35

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);
}
Rahul Bhobe
  • 4,165
  • 4
  • 17
  • 32
Madiyar
  • 779
  • 11
  • 7
  • I don't think `std::ignore` ca be used in structured bindings in this way. I'm getting a compile error. It should be sufficient to just use a regular variable e.g. `ignored` that simply doesn't get used. – j b Mar 31 '20 at 10:02
  • 2
    @j-b Thanks. Indeed, `std::ignore` is intended for use with `std::tie` but not with structural bindings. I've updated my code. – Madiyar Apr 12 '20 at 11:23
22

@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.

James Hirschorn
  • 7,032
  • 5
  • 45
  • 53
  • 9
    You could add `keys.reserve(map_in.size());` for efficiency. – Galik Apr 04 '18 at 18:18
  • 1
    I find the transform method actually takes more code than for-loop. – user1633272 Nov 05 '18 at 08:00
  • const can be put behind the type! I almost forget that. – Zhang May 06 '19 at 08:58
  • @user1633272> yes, but that's not how you measure if it is good. `a`, `b`, `c` take less code than `author`, `book`, `customer`, yet no seasoned developer would tell you to prefer them. Production code is not code golf ;) – spectras Nov 17 '21 at 15:26
  • I would never call a variable `pair`, especially after `using namespace std` (in this case I use the name `entry`) – Antonio May 11 '22 at 12:41
15

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
}
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
12

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

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
8

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.

oz10
  • 153,307
  • 27
  • 93
  • 128
8

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;
}
Rusty Parks
  • 173
  • 1
  • 8
8

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

Clemens Sielaff
  • 708
  • 10
  • 15
7

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

Marcelo Cantos
  • 181,030
  • 38
  • 327
  • 365
7

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

Using ranges in C++20 you can use std::ranges::copy like this

#include <ranges>
std::map<int,int> mapints;
std::vector<int> vints;

std::ranges::copy(mapints | std::views::keys, std::back_inserter(vints));

if you want values instead of keys

std::ranges::copy(mapints | std::views::values, std::back_inserter(vints));

and if you don't like the pipe syntax

std::ranges::copy(std::views::values(mapints), std::back_inserter(vints));
Olppah
  • 790
  • 1
  • 10
  • 21
6

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

amit kumar
  • 20,438
  • 23
  • 90
  • 126
4

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];
Marius
  • 3,372
  • 1
  • 30
  • 36
  • 1
    I'll leave it to the reader to also create the const_iterator and reverse iterators if/when needed. – Marius Mar 05 '10 at 19:29
4

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.

Chrissi
  • 189
  • 1
  • 8
1

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
KaiserKatze
  • 1,521
  • 2
  • 20
  • 30
1

With Eric Niebler's range-v3 library, you can take a range and write it out directly to a container using ranges::to (hopefully soon in std, maybe C++26?):

[Demo]

#include <fmt/ranges.h>
#include <map>
#include <range/v3/all.hpp>

int main() {
    std::map<int, int> m{ {1, 100}, {2, 200}, {3, 300} };
    auto keys{ m | ranges::views::keys | ranges::to<std::vector<int>>() };
    fmt::print("{}", keys);
}

// Outputs: [1, 2, 3]
rturrado
  • 7,699
  • 6
  • 42
  • 62
0

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;
}
Deniz Babat
  • 205
  • 2
  • 6
0

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;
}
uol3c
  • 559
  • 5
  • 9
-2

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);
TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
  • 2
    Hey, I know this answer is old but it's also wrong. Initializing with size `map.size()` means double the vector size return. Please fix to save someone else the headache :( – thc Jul 03 '19 at 23:44
-4

(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.

DrPizza
  • 17,882
  • 7
  • 41
  • 53
  • 9
    There are reasons other than efficiency for a library to provide a method, such as "batteries included" functionality, and a coherent, encapsulated API. Although admittedly neither of those terms describe the STL particularly well :) Re. not clear why it's useful -- really? I think it's pretty obvious why listing the available keys is a useful thing to be able to do with a map/dict: it depends on what you're using it for. – andybuckley Dec 16 '12 at 14:19
  • 5
    By this reasoning, we should't have `empty()` because it can be implemented as `size() == 0`. – gd1 Oct 01 '15 at 08:49
  • 1
    What @gd1 said. While there shouldn't be a lot of functional redundancy in a class, insisting on absolutely zero is not a good idea IMO - at least until C++ allows us to "bless" free functions into methods. – einpoklum Feb 02 '16 at 19:15
  • 1
    In older versions of C++ there were containers for which empty() and size() could reasonably have different performance guarantees, and I think the spec was sufficiently loose as to permit this (specifically, linked lists that offered constant-time splice()). As such, decoupling them made sense. I don't think this discrepancy is permitted any more, however. – DrPizza Apr 08 '16 at 23:11
  • I agree. C++ treats `std::map` as a container of pairs. In Python, a `dict` acts like its keys when iterated over, but lets you say `d.items()` to get the C++ behavior. Python also provides `d.values()`. `std::map` certainly could provide a `keys()` and `values()` method that return an object that has `begin()` and `end()` that provide iterators over the keys and values. – Ben Jul 10 '17 at 17:02
  • c# has such method. I think that having such function is merely about the mindset (type theory and object oriented and functionnal mindset). It seems to me that DrPizza has an imperative and performance centric point of view (which is, in the end it's always what happens after compilation, and after the front end). Ina nutshell: should we think like mathematicians (with concepts) or like mecanicians (with what/how to do) ? – Soleil Oct 02 '20 at 16:18