How to retrieve all keys (or values) from a std::map and put them into a vector? covers the ways to populate a std::vector from the keys in a map pre-C++11.
Is there a way to do this in C++11 using lambdas, etc, that means we can do it in one line so we can initialize the vector from the map instead of create a vector and populate it in 2 actions?
e.g. vector<int> v(???(m.begin(),m.end()));
Pure C++11 is preferred but boost is acceptable... the aim is to do this in one line without it being overly complicated and "showing off", so it's not confusing to other developers.
For comparison the "obvious" C++11 solution is:
vector<int> v;
v.reserve(m.size()); //not always needed
for(auto &x : map)
v.push_back(x.first)
In C++ we can use arrays or vector as a key against to a int value like: map<vector<int> ,int > m; Can I do same in MATLAB by containers.
For the hashmap, we can use the inserted value as the key and its vector index as the corresponding hashmap value.
One way to initialize a map is to copy contents from another map one after another by using the copy constructor. Syntax: map<string, string>New_Map(old_map);
You can initialize a vector by using an array that has been already defined. You need to pass the elements of the array to the iterator constructor of the vector class. The array of size n is passed to the iterator constructor of the vector class.
Use boost::adaptor::map_keys
in Boost.Range.
#include <iostream>
#include <vector>
#include <map>
#include <boost/range/adaptor/map.hpp>
int main()
{
const std::map<int, std::string> m = {
{1, "Alice"},
{2, "Bob"},
{3, "Carol"}
};
auto key_range = m | boost::adaptors::map_keys;
const std::vector<int> v(key_range.begin(), key_range.end());
for (int x : v) {
std::cout << x << std::endl;
}
}
Output:
1
2
3
There you go, C++11 one-liner :)
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
int main(int, char**)
{
std::map<int, std::string> map {
{1, "one"},
{2, "two"},
{3, "three"}
};
std::vector<int> keys;
// Reserve enough space (constant-time)
keys.reserve(map.size());
// Retrieve the keys and store them into the vector
std::transform(map.begin(), map.end(), std::back_inserter(keys),
[](decltype(map)::value_type const &pair) {return pair.first;}
);// ^^^^^^^^^^^^^^^^^^^^^^^^^ Will benefit from C++14's auto lambdas
// Display the vector
std::copy(keys.begin(), keys.end(),
std::ostream_iterator<int>(std::cout, " "));
return 0;
}
std::transform
is freaking powerful.
Something like the following would do:
#include <vector>
#include <map>
#include <boost/iterator/transform_iterator.hpp>
int main() {
std::map<std::string, int> m{{"abc", 1}, {"def", 2}};
auto extractor = [](decltype(m)::value_type const& kv) { return kv.first; };
std::vector<std::string> v(
boost::make_transform_iterator(m.begin(), extractor)
, boost::make_transform_iterator(m.end(), extractor)
);
}
Note that passing iterators to vector
's constructor is the most efficient way to initialize a vector
compared to solutions that use push_back
or resize
a vector filling it with default values first.
No, there's no way to do this in pure C++11 in one line using any of std::vector
s constructor overloads, without e.g. creating your own iterator adaptor.
It's trivial to do in two lines though, e.g.:
std::vector<Key> v;
for (const auto& p : m) v.push_back(p.first);
It would also be easy to create your own iterator adaptor for this purpose, for example:
template <typename InputIt>
struct key_it : public InputIt {
key_it(InputIt it) : InputIt(it) {}
auto operator*() { return (*this)->first; }
};
// Helper function for automatic deduction of iterator type.
template <typename InputIt>
key_it<InputIt> key_adapt(InputIt it) {
return {it};
}
Now you can create and populate your std::vector
in one line using:
std::vector<Key> v{key_adapt(std::begin(m)), key_adapt(std::end(m))};
Live example
A slight refinement of Quentin's solution:
std::vector<int> keys(map.size());
transform(map.begin(), map.end(), keys.begin(),
[](std::pair<int, std::string> const &p) { return p.first; });
or more readably:
std::vector<int> keys(map.size());
auto get_key = [](std::pair<int, std::string> const &p) { return p.first; };
transform(map.begin(), map.end(), keys.begin(), get_key);
probably better having:
int get_key(std::pair<int, std::string> const &p) { return p.first; }
std::vector<int> get_keys(const std::map<int, std::string> &map)
{
std::vector<int> keys(map.size());
transform(map.begin(), map.end(), keys.begin(), get_key);
return keys;
}
then calling:
std::vector<int> keys = get_keys(map);
if it's going to be used lots.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With