我必须像这样转换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万个元素。这是我在太空浪费和时间方面找到的最佳解决方案;有没有更好的方法来做这项工作?
答案 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
,这是一个巨大的性能优势,因为输入范围已经按相同的顺序排序,因此每次连续插入都与最后一个插入相邻。