简介
有时需要对map中的key进行一些单独的处理,这时将它们拷贝到一个vector中再处理会方便些。
以下方法对unordered_map同样适用。以key为string类型为例。
先介绍几种获取map中key的方法,对于获取set中key的方法,与map类似。文末简要介绍。
遍历取值
这是普通朴素的方法,直接上代码:
// 省略头文件和using声明
template<typename T>
void MapKeysToVector(const T& in, vector<string>& out)
{
out.reserve(in.size()); // 提前为vector分配空间,避免因为中途空间重新分配损失效率
for (const auto& data : in) {
out.emplace_back(data.first); // c11的emplace_back()比push_back()高效,置入比插入省略了临时中间对象的构造过程
}
}
transform + boost
使用标准算法同样达到目的:
#include <string>
#include <map>
#include <vector>
#include <algorithm>
#include <boost/bind.hpp>
int main()
{
typedef std::map<std::string, int> MapT;
typedef std::vector<std::string> VecT;
MapT map;
VecT vec;
map["one"] = 1;
map["two"] = 2;
map["three"] = 3;
map["four"] = 4;
map["five"] = 5;
std::transform( map.begin(), map.end(),
std::back_inserter(vec),
boost::bind(&MapT::value_type::first, _1) ); // use boost::bind to access the first or second value of the pair
}
transform + lambda
上述使用boost::bind的方法可以使用lambda替换:
#include <algorithm> // std::transform
#include <iterator> // std::back_inserter
std::transform(
map.begin(),
map.end(),
std::back_inserter(vec), // 需要使用back_inserter,它会自动为vector分配空间
[](auto &kv){ return kv.first;} // 返回输入迭代器的key,需要c++14
);
std::for_each
使用for_each迭代结合lambda:
{
std::map<std::string,int> m;
std::vector<int> v;
v.reserve(m.size()); // 提前分配好空间
std::for_each(m.begin(),m.end(),
[&v](const std::map<std::string, int>::value_type& p)
{ v.push_back(p.first); });
}
boost
使用boost库提供的函数boost range adaptor
,如下:
#include <boost/range/adaptor/map.hpp>
#include <boost/range/algorithm/copy.hpp>
map<string, int> m;
// ...
// insert values to m
vector<string> keys;
boost::copy(m | boost::adaptors::map_keys, std::back_inserter(keys));
小结
以上方法能够获取map的keys到vector,稍做修改,就可以获取到map的value到vector。
具体使用时,可根据项目组的使用习惯选择。如果对boost不熟悉,不建议选择boost方法,这会增加学习维护成本。
如果对stl算法库也不熟悉,建议使用最朴素的解法。这样你的同事也可以轻易理解并维护代码。
setkeyvector_116">获取set的key到vector
对于set比较简单,因为它不是std::pair类型的数据。
直接上方法:
set<string> input; // insert values to input
// 遍历取值方式略
// 直接std::copy,需要使用std::back_inserter
std::copy(input.begin(), input.end(), std::back_inserter(output));
// 先分配内存,再直接copy
std::vector<string> output(input.size());
std::copy(input.begin(), input.end(), output.begin());
// range constructor
std::vector<string> output(input.begin(), input.end());
// vector.assign()
vector<string> v;
v.assign(input.begin(), input.end());
总结
- 根据代码便于维护原则,选择项目组最熟悉的方法即可
- 根据代码简洁原则,选择使用stl算法,如transform/copy
- 如果经常使用boost库,可以选择boost
- 对于set比较简单,使用直接构造或者assign更简洁