Obtaining list of keys and values from unordered_map
Solution 1
Okay, here you go:
std::vector<Key> keys;
keys.reserve(map.size());
std::vector<Val> vals;
vals.reserve(map.size());
for(auto kv : map) {
keys.push_back(kv.first);
vals.push_back(kv.second);
}
Efficiency can probably be improved, but there it is. You're operating on two containers though, so there's not really any STL magic that can hide that fact.
As Louis said, this will work for any of the STL map
or set
containers.
Solution 2
Using C++-14 you could also do the following (edited to contain full source):
#include <algorithm>
#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
using namespace std;
typedef string Key;
typedef int Value;
auto key_selector = [](auto pair){return pair.first;};
auto value_selector = [](auto pair){return pair.second;};
int main(int argc, char** argv) {
// Create a test map
unordered_map<Key, Value> map;
map["Eight"] = 8;
map["Ten"] = 10;
map["Eleven"] = 11;
// Vectors to hold keys and values
vector<Key> keys(map.size());
vector<Value> values(map.size());
// This is the crucial bit: Transform map to list of keys (or values)
transform(map.begin(), map.end(), keys.begin(), key_selector);
transform(map.begin(), map.end(), values.begin(), value_selector);
// Make sure this worked: Print out vectors
for (Key key : keys) cout << "Key: " << key << endl;
for (Value value : values) cout << "Value: " << value << endl;
return 0;
}
I compiled this with the following command:
g++ keyval.cpp -std=c++14 -o keyval
Testing it printed the keys and values as expected.
Solution 3
In STL there is no built-in method to get all keys or values from a map.
There is no different to iterate a unordered map or regular map, the best way is to iterate it and collect key or value to a vector.
You can write a template function to iterate any kind of map.
Solution 4
Joining late, but thought this might be helpful to someone.
Two template functions making use of key_type
and mapped_type
.
namespace mapExt
{
template<typename myMap>
std::vector<typename myMap::key_type> Keys(const myMap& m)
{
std::vector<typename myMap::key_type> r;
r.reserve(m.size());
for (const auto&kvp : m)
{
r.push_back(kvp.first);
}
return r;
}
template<typename myMap>
std::vector<typename myMap::mapped_type> Values(const myMap& m)
{
std::vector<typename myMap::mapped_type> r;
r.reserve(m.size());
for (const auto&kvp : m)
{
r.push_back(kvp.second);
}
return r;
}
}
Usage:
std::map<long, char> mO;
std::unordered_map<long, char> mU;
// set up the maps
std::vector<long> kO = mapExt::Keys(mO);
std::vector<long> kU = mapExt::Keys(mU);
std::vector<char> vO = mapExt::Values(mO);
std::vector<char> vU = mapExt::Values(mU);
Related videos on Youtube
Faheem Mitha
Updated on January 23, 2022Comments
-
Faheem Mitha over 2 years
What is the most efficient way of obtaining lists (as a
vector
) of the keys and values from anunordered_map
?For concreteness, suppose the map in question is a
unordered_map<string, double>
. I'd then like to obtain the keys as avector<string>
, and the values as avector<double>
.unordered_map<string, double> um; vector<string> vs = um.enum_keys(); vector<double> vd = um.enum_values();
I can just iterate across the map and collect the result, but is there a more efficient method? It would be nice to have a method that also works for regular map, since I might switch to that.
-
Keith Layne over 12 yearsLooking at the draft standard, I don't see an easy way to get what you want, but I may be missing something. You could say
std::vector<std::pair<const Key, Val>> v(map.begin(), map.end());
which should give you a vector of key-value pairs. -
Faheem Mitha over 12 years@keith.layne: I'm looking for separate vectors for keys and values.
-
Keith Layne over 12 yearsAs I said, there's nothing built-in for that. See below.
-
Faheem Mitha over 12 years@muntoo: Not sure what is with the edit. What is
vector<string> vs = um.enum_keys();
supposed to signify? -
Mooing Duck over 12 yearsBoost has a transform iterator which can pull just keys or just values, but its faster to do both at once as Keith suggests
-
Mateen Ulhaq over 12 years@FaheemMitha Just making it 'better'. If you don't like it, you can remove it.
enum_keys()
doesn't exist, but that is the 'format' you want it in, so I thought I'd clarify. -
Faheem Mitha over 12 years@MooingDuck: Feel free to add a answer using transform. I think it would be useful in cases when someone just wants one of these.
-
Mooing Duck over 12 years@FaheemMitha: It turns out to not be a good answer to your particular situation since you want both, but it's described and shown in other questions: stackoverflow.com/a/2794168/845092
-
Faheem Mitha over 12 years@MooingDuck: You could still add an answer, but whatever. The interesting question is whether these fancy methods are faster than the regular ones. I guess one could time them and find out.
-
Mooing Duck over 12 years@FaheemMitha: The boost answer isn't faster than keith.layne's answer. It's mostly useful if you want to return an iterator to just keys, or just values for a
iter<key> get_keys()
function. -
Faheem Mitha over 12 years@MooingDuck: Ok. Thanks for the clarification.
-
-
Faheem Mitha over 12 yearsOk, sO I guess there is nothing better than iterating over the map then. I don't recognize the syntax you are using. What does
(auto kv : map)
denote. I would have expected just an iteration (i.e. for loop) over the elements of the map. -
Keith Layne over 12 years@FaheemMitha That is the new C++11 for loop. It does exactly what it looks like it does, and combined with
auto
makes things a little more tidy.auto
saves you from having to explicitly write the type of kv. There are several ways to accomplish essentially the same thing including a for loop over the iterators,for_each
with a lambda, etc. Since you mentionedunordered_map
I assumed you were using C++11. -
Faheem Mitha over 12 yearsI guess I am, but I'm not really familar with the new standard. Thanks.
-
Mooing Duck over 12 yearsEffienency can be improved with a reserve, but not much will be faster or easier than this.
-
Whitecat over 8 yearsCan you explain this more
-
Faheem Mitha over 8 yearsCould you write a self-contained example that can be compiled? Also, if you could mention what compiler to use and provide a command line to use to compile it, that would be helpful. thanks.
-
Faheem Mitha over 8 yearsAlso, what are
Key
andValue
andum
here? You haven't defined them. Perhaps you are using the definition from the question, namely "unordered_map<string, double> um;", but in that case, you should mention that here again, regardless. -
Marius Renn over 8 yearsSorry folks, was on the bus when I wrote this and stayed rather brief. I now updated the code to something that should compile. Let me know if it does not work. The way this works is that we apply a lambda function to each element of the map (which is a key-value pair). The key-selector simply returns the first element of the pair, while the value selector returns the second. We use the transform function to copy the keys (or values) to the vectors. I am not an expert in std library's algorithms so there may be a more elegant way.
-
Faheem Mitha over 8 yearsWorks here with clang 3.5 and gcc 4.9. Has this any efficiency advantages relative to a plain loop?
-
minexew over 8 yearsProbably not very efficient due to use of a lambda function, but very elegant as a functional algorithm.
-
Paul Rooney almost 8 yearsThe lambas should introduce no overhead they (like any other functors) can be inlined into the
transform
loop. But when usingauto
be sure to remember it deduces value types, so those range based for loops introduce some copies. You can useconst auto&
instead of plainauto
, where it makes sense to. -
Juicebox about 7 yearsI would use
auto&
instead ofauto
here to avoid unnecessary copies of the pair (and underlying first/second members if they are structs). And it won't work forset
containers because theirvalue_type
is not astd::pair<K, V>
but the Key/Val type itself. -
John Phu Nguyen almost 7 yearsToday's compilers will almost certainly inline the lambda without even requiring the keyword. There will be no performance hit.
-
fire in the hole over 4 yearsinstead of
std::vector<Key> keys; keys.reserve(map.size());
you can writestd::vector<Key> keys(map.size());
same with the other vector