C++ 从地图中获取值列表
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4195611/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Getting a list of values from a map
提问by Amir Rachum
Is there an stl way to get a list of values from a map?
有没有一种 stl 方法可以从地图中获取值列表?
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?
并且我想要一个仅返回值列表的函数,即,std::list<B>
(或为此设置。是否有内置的 stl 方法来执行此操作?
回答by John Dibling
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 functorto 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.
一个map
元素被定义为 a map::value_type
,它的类型是 a pair<A,B>
。 first
是关键,second
也是价值。您可以编写一个函子second
从 a 中提取 value_type
,然后将其复制到 a vector
(或 a list
,或任何您想要的)中。进行复制的最佳方法是使用transform
,它的作用正如其名称所暗示的那样:它需要一个值一种类型并将其转换为不同类型的值。
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:
如果您有一个支持 C++0x lambdas的编译器,您可以完全消除函子。这对于使代码更具可读性和易于维护非常有用,因为您最终不会在代码库中漂浮着数十个一次性的小函子。以下是如何更改上面的代码以使用 lambda:
transform(my_map.begin(), my_map.end(), back_inserter(my_vals), [](const MyMap::value_type& val){return val.second;} );
回答by Rob Kennedy
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.
没有内置任何东西,没有。不过,编写自己的函数很简单:迭代地图。迭代器会给你一个pair<A, B>
. 将每个second
值添加到结果列表中。
回答by Johann Gerell
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.
许多“内置”方式之一当然是最明显的一种。只需遍历按键 ( pair::first
)排序的所有 pair 元素,并将值 ( pair::second
)添加到新容器中,您可以使用正确的容量构造该容器,以在迭代和添加期间摆脱多余的分配。
Just a note: std::list
is seldom the container you actually want to be using. Unless, of course, you really, really doneed its specific features.
请注意:std::list
很少是您真正想要使用的容器。当然,除非,你真的,真的就需要其特定的功能。
回答by aschepler
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:
或者如果你真的喜欢更多的 STL 方式:
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());
回答by Puppy
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.
如果你没有 C++0x 编译器,首先你有我的同情,其次,你需要为此目的构建一个快速的函数对象。
回答by Ben
You can use boost's transform_iterator
: http://www.boost.org/doc/libs/1_64_0/libs/iterator/doc/transform_iterator.html
您可以使用 boost 的transform_iterator
:http: //www.boost.org/doc/libs/1_64_0/libs/iterator/doc/transform_iterator.html
struct GetSecond {
template <typename K, typename T>
const T& operator()(const std::pair<K, T> & p) const { return p.second; }
template <typename K, typename T>
T& operator()(std::pair<K, T> & p) const { return p.second; }
};
template <typename MapType>
auto begin_values(MapType& m) -> decltype(boost::make_transform_iterator(m.begin(), GetSecond())) {
return boost::make_transform_iterator(m.begin(), GetSecond());
}
template <typename MapType>
auto end_values(MapType& m) -> decltype(boost::make_transform_iterator(m.end(), GetSecond())) {
return boost::make_transform_iterator(m.end(), GetSecond());
}
template <typename MapType>
struct MapValues {
MapType & m;
MapValues(MapType & m) : m(m) {}
typedef decltype(begin_values(m)) iterator;
iterator begin() { return begin_values(m); }
iterator end() { return end_values(m); }
};
template <typename MapType>
MapValues<MapType> get_values(MapType & m) {
return MapValues<MapType>(m);
}
int main() {
std::map<int, double> m;
m[0] = 1.0;
m[10] = 2.0;
for (auto& x : get_values(m)) {
std::cout << x << ',';
x += 1;
}
std::cout << std::endl;
const std::map<int, double> mm = m;
for (auto& x : get_values(mm)) {
std::cout << x << ',';
}
std::cout << std::endl;
}