Initialize a container with iterator range of container with different type

夙愿已清 提交于 2020-01-03 15:21:13

问题


Let's say we have std::set<int> and we want to create a std::vector<int> with all values from that set:

std::set<int> set;
std::vector<int> vec( set.begin(), set.end() );

This is simple and elegant. But let's say I have a std::map<std::string,int> and I want to copy all values to std::vector<int>. Unfortunately there is no constructor, that accepts range of iterators and converter function. Why there is no such constructor provided? Is there another simple and elegant way to initialize one container with different type values?


回答1:


Use transform iterators:

#include <boost/iterator/transform_iterator.hpp>
#include <vector>
#include <map>

int main() {
    std::map<int, double> m;
    auto f = [](auto&& pair) { return pair.second; };
    std::vector<double>(boost::make_transform_iterator(m.begin(), f),
                        boost::make_transform_iterator(m.end(), f));
}

Alternatively, use boost::adaptors:

#include <boost/range/adaptor/map.hpp>
#include <vector>
#include <map>

int main() {
    std::map<int, double> m;
    auto range = boost::adaptors::values(m);
    std::vector<double>(range.begin(), range.end());
}

Or the same as above:

    auto v = boost::copy_range<std::vector<double> >(boost::adaptors::values(m));

Note that using vector's range constructor is more efficient than a solution involving back_inserter.




回答2:


With boost::transform_iterator:

#include <functional>
#include <boost/iterator/transform_iterator.hpp>

std::map<std::string, int> m{ {"a", 1}, {"b", 2} };
auto second = std::mem_fn(&std::map<std::string, int>::value_type::second);

std::vector<int> vec(boost::make_transform_iterator(std::begin(m), second)
                   , boost::make_transform_iterator(std::end(m), second));

DEMO




回答3:


std::map has another memory model, storing values as std::pair. Unpacking these isn't the job of a constructor. You can create your vector, reserve memory equal to the map size and iterate over map pairs to push your integers to the back of your vector. std::transform slims that.




回答4:


I think the best you can do is using range based cycles or for_each function.



来源:https://stackoverflow.com/questions/32377304/initialize-a-container-with-iterator-range-of-container-with-different-type

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!