将std::map复制到std::vector的pair中

20

我正在尝试将一个地图拷贝到一个pair类型的向量中,以便我可以通过这些pair的second数据成员对向量进行排序。我已经解决了这个问题,方法如下:

void mappedWordsListSorter(){
  for (auto itr = mappedWordsList.begin(); itr != mappedWordsList.end(); ++itr){
    vectorWordsList.push_back(*itr);
  }
  sort(vectorWordsList.begin(), vectorWordsList.end(), [=](pair<string, int>& a, pair<string, int>& b){return a.second > b.second;});
}

我需要找到一种方法,在不使用原始循环的情况下,使用标准库来实现。我已经遇到了很多示例,只传输映射的键或值中的一个。我需要将它们复制到pairs<string, int>的向量中。最好的方法是什么?


1
@Lorand - 排序发生在对中的第二个项目上,而不是键。 - StoryTeller - Unslander Monica
1
@Lorand 看起来 OP 想要根据值而不是键进行排序。 - JFMR
3
似乎应将该问题标记为与此问题重复,因为@NathanOliver提供的答案比那个问题的任何答案都要好。编辑说明:尽管该问题包括对结果进行排序。 - François Andrieux
1
@ALX23z - 我同意 [=] 不应该存在。但仅仅因为它存在并不意味着 所有东西 都会被复制。Lambda 表达式必须从周围的作用域中使用某些内容来捕获它。 - StoryTeller - Unslander Monica
1
@ALX23z 实际上,只有在 lambda 主体中使用变量时,它才会复制一个变量。如果您不使用作用域中的任何变量,则使用 [=] 不会产生性能损失。 - NathanOliver
显示剩余4条评论
3个回答

26

可以直接使用std::vectorassign成员函数。

//no need to call reserve, bidirectional iterators or better will compute the size and reserve internally.
vectorWordsList.assign(mappedWordsList.begin(), mappedWordsList.end());

如果您的向量中有现有值,不想被覆盖,那么请使用insert,例如:

vectorWordsList.reserve(vectorWordsList.size() + mappedWordsList.size()); // make sure we only have a single memory allocation
vectorWordsList.insert(vectorWordsList.end(), mappedWordsList.begin(), mappedWordsList.end());

1
我希望assign在内部基本上是reserve - François Andrieux
10
如果使用随机访问迭代器,它很可能会这样做,但由于map具有双向迭代器,需要遍历以确定要分配多少元素的空间,因此它不会这样做。 - NathanOliver
1
@NathanOliver libstdc++ 实际上在内部基本上执行了 reserve 操作。对于任何 ForwardIterator,它将调用 std::distance,为不是 RandomAccessIterator 的任何类型付出遍历代价。您可以跟踪 std::vector::assign此处 - Justin
1
@Justin Cool。谢谢你找到了那个。我仍然喜欢明确表示,以防其他实现不这样做。 - NathanOliver
由于assign不需要MoveInsertable,如果迭代器是前向或更强,则必须保留并且不能重新分配内存。此外,对于第二种情况,reserve是一种反模式(它会防止指数增长并可能导致二次行为)。 - T.C.
显示剩余2条评论

10

值得注意的是,如果你正在为此创建一个向量,你可以直接使用向量的构造函数:

std::vector<std::pair<FirstType,SecondType>> vectorWordsList( mappedWordsList.begin(), mappedWordsList.end() );
在C++17中,您还可以省略vector的模板参数,以便让编译器推断它们:
std::vector vectorWordsList( mappedWordsList.begin(), mappedWordsList.end() );

除非你想创建一个迭代器向量,否则你需要使用括号。 - T.C.

7
您可以使用std::copystd::back_inserter
std::copy(mappedWordsList.begin(), 
          mappedWordsList.end(), 
          std::back_inserter(vectorWordsList));

老实说,我认为使用范围for循环更加清晰:
for(const auto& kv : mappedWordsList) 
     vectorWordsList.emplace_back(kv);

无论如何,您都可以使用std::vector::reserve在目标vector上预分配内存,避免不必要的重新分配。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接