C ++转换map <int,set <int =“”>&gt;到map <int,vector <int =“”>&gt; </int,> </int,>

时间:2013-02-08 10:33:20

标签: c++ map vector set move

我必须像这样转换std :: map:

std::map<int, std::set<int> > t_contents;

在这样的地图中:

std::map<int, std::vector<int> > seq;

我正在以这种方式进行转换:

std::map<int, std::set<int> >::const_iterator it;
for(it = t_contents.begin(); it != t_contents.end(); ++it)
{    
    std::move((*it).second.begin(), (*it).second.end(), 
        std::back_inserter(seq[(*it).first])
    );   
}

考虑到地图包含多达100万个元素,每个集合也可以包含1万个元素。这是我在太空浪费和时间方面找到的最佳解决方案;有没有更好的方法来做这项工作?

2 个答案:

答案 0 :(得分:3)

如果使用提示插入,性能会更好(每次插入的摊销常数):

std::map<int, std::set<int> >::const_iterator it;
for (it = t_contents.begin(); it != t_contents.end(); ++it) {
    std::vector<int> &vec = seq.insert(seq.end(),
        std::make_pair(it->first, std::vector<int>()))->second;
    vec.reserve(it->second.size());
    vec.assign(it->second.begin(), it->second.end());
}

使用reserve来防止重新分配,并将vector::assign与迭代器参数一起使用;它比back_inserter更具可读性(如果没有效率)。

另一种方法是将矢量直接放入地图中,仍使用提示:

std::map<int, std::set<int> >::const_iterator it;
for (it = t_contents.begin(); it != t_contents.end(); ++it) {
    seq.emplace_hint(seq.end(), it->first,
        std::vector<int>(it->second.begin(), it->second.end());
}

请注意,不需要move设置元素;因为它们是原始的,所以移动与副本相同。

这可能更快或更慢,具体取决于例如关于insert是否检查迭代器参数之间的距离(在任何情况下它都是设置大小的O(n))。

答案 1 :(得分:3)

另一种选择是:

std::transform(t_contents.begin(), t_contents.end(), std::inserter(seq.begin()),
  [](const std::pair<const int, std::set<int>>& s) {
    std::vector<int> v;
    v.reserve(s.second.size());
    v.assign(s.second.begin(), s.second.end());
    return std::make_pair(s.first, std::move(v));
  }
);

移动int是没有意义的,std::set迭代器无论如何都是const,所以你不能移出一个集合。

就像ecatmur的回答一样,这有利于插入提示,因为insert_iterator的每个赋值都使用前一个插入点作为提示insert,这是一个巨大的性能优势,因为输入范围已经按相同的顺序排序,因此每次连续插入都与最后一个插入相邻。

相关问题