Getting a list of values from a map
Solution 1
A map
element is defined as a map::value_type
, and the type of it is a pair<A,B>
. first
is the key and second
is the value. You can write a functor to extract second
from a value_type
, and copy that in to a vector
(or a list
, or whatever you want.) The best way to do the copying is to use transform
, which does just what its name implies: it takes a value of one type and transforms it to a different type of value.
Here's a complete working example:
#include <cstdlib>
#include <map>
#include <string>
#include <algorithm>
#include <iterator>
#include <vector>
#include <iostream>
using namespace std;
typedef map<unsigned, string> MyMap;
MyMap my_map;
struct get_second : public std::unary_function<MyMap::value_type, string>
{
string operator()(const MyMap::value_type& value) const
{
return value.second;
}
};
int main()
{
my_map[1] = "one";
my_map[2] = "two";
my_map[3] = "three";
my_map[4] = "four";
my_map[5] = "five";
// get a vector of values
vector<string> my_vals;
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), get_second() );
// dump the list
copy( my_vals.begin(), my_vals.end(), ostream_iterator<string>(cout, "\n"));
}
EDIT:
If you have a compiler that supports C++0x lambdas, you can eliminate the functor entirely. This is very useful for making code more readable and, arguable, easier to maintain since you don't end up with dozens of little one-off functors floating around in your codebase. Here's how you would change the code above to use a lambda:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
Solution 2
There's nothing built in, no. It's simple enough to write your own function, though: Iterate over the map. The iterator will give you a pair<A, B>
. Add each second
value to the result list.
Solution 3
You can't just "get" such a list because there is no pre-existing list stored anywhere in the guts, but you can build one:
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
for (myMapType::const_iterator it=myMap.begin(); it!=myMap.end(); ++it) {
valueList.push_back( it->second );
}
Or if you really like the more STL way:
class GetSecond {
template<typename T1, typename T2>
const T2& operator()( const std::pair<T1,T2>& key_val ) const
{ return key_val.second; }
};
typedef std::map<A,B> myMapType;
myMapType myMap;
std::list<B> valueList;
std::transform(myMap.begin(), myMap.end(), std::back_inserter(valueList),
GetSecond());
Solution 4
One of many "built-in" ways is of course the most obvious one. Just iterate over all pair elements, which are ordered by key (pair::first
), and add the value (pair::second
) to a new container, which you can construct with the correct capacity to get rid of excess allocations during the iteration and adding.
Just a note: std::list
is seldom the container you actually want to be using. Unless, of course, you really, really do need its specific features.
Solution 5
Sure.
std::list<B> list;
std::for_each(myMap.begin(), myMap.end(), [&](const std::pair<const A, B>& ref) {
list.push_back(ref.second);
});
If you don't have a C++0x compiler, first you have my sympathies, and second, you will need to build a quick function object for this purpose.
Amir Rachum
Programmer, Board Gamer, Geek. Blog, Resume and Projects: http://amir.rachum.com/blog Twitter: @AmirRachum
Updated on July 09, 2022Comments
-
Amir Rachum almost 2 years
Is there an stl way to get a list of values from a map?
i.e, I have:
std::map<A,B> myMap;
and I would like a function that will return just the list of values, i.e,
std::list<B>
(or set for that matter. Is there a built-in stl way to do this? -
James McNellis over 13 yearsWhere's the
std::transform
love? -
James McNellis over 13 yearsUnfortunately, there is no
select2nd
in the C++ Standard Library. -
John Dibling over 13 yearsI would consider
transform
and the idea of functors to be more or less built-in -
John Dibling over 13 years@DeadMG: lambdas are beyond the domain because this question isn't tagged [c++0x]
-
John Dibling over 13 years@DeadMG: Nonetheless, I will ammend my answer to include a lamda example
-
aschepler over 13 yearsYeah, I noticed too late. I'm about to stop bothering with the darn SGI "documentation".
-
Puppy over 13 years@John Dibling: Lambda support stopped having to be explicitly tagged when MSVC10 and GCC4.5 both support them.
-
John Dibling over 13 years@DeadMG: Really? Even though C++ and C++0x are not the same?
-
aschepler over 13 years@DeadMG: I disagree. Like it or not, many C++ programmers are not already using the latest and best compilers on the most popular OSes, because of legacy code, business decisions, and/or coding standards that do not yet allow using the new unofficial features for more portability.
-
Puppy over 13 years@John: Yes. I expect that plenty of people are using a lambda-supporting compiler. @aschepler: That's true. But I'm hardly using some feature or library that's totally untranslatable to C++03, like perfect forwarding. It's just slightly less convenient. It's not like you can't make this answer work in C++03 without a ton of effort.
-
Rob Kennedy over 13 years@John. by saying "built in," I interpret the question to request PHP's
array_values
or Perl'svalues
— the library provides a function tailored exactly to the task, rather than just a bunch of pieces that you have to put together to write avalues
function of your own. Things are worse if your compiler or library doesn't provide all the best pieces (likeselect2nd
or lambdas). -
John Dibling over 13 years@DeadMG: Because at the end of the day, since C++0x isn't even official yet, C++ and C++0x are different languages, and by your logic one might conclude that is a question is tagged only [c] it is reasonable to answer with C++ constructs. Maybe a bit extreme, but I trust you get my point.
-
Puppy over 13 years@John: No, I don't get your point. C++ and C are radically different languages. C++03 and C++0x are not radically different languages- they're exceedingly similar and especially in the area which my answer concerned, it is trivial to convert to C++03. Should we ask people whether they mean C++ or C when they ask if
++a++a++=a
is undefined? -
Wheezil about 3 yearsEven more succinct: transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const auto& val){return val.second;} );