将 std::map 转换为有序的 std::vector
Posted
技术标签:
【中文标题】将 std::map 转换为有序的 std::vector【英文标题】:Transforming std::map into ordered std::vector 【发布时间】:2020-07-16 14:02:33 【问题描述】:我有一个std::map
,它存储一个字符串和一个类,我想根据类属性的值创建一个有序向量。但是,当我遍历向量时,什么都不会打印。到目前为止,我的代码是这样的,编译器没有发现任何错误:
void Championship::orderTeams(std::vector<std::pair<std::string, class Team> > vect, std::map<std::string, class Team>& map)
for (auto const& entry : map)
if (vect.empty()) //check if vector is empty and add the first pair
vect.push_back(std::make_pair(entry.first, entry.second));
continue;
for (auto pos = vect.begin(); pos != vect.end(); ++pos)
if(entry.second.points > pos->second.points)
vect.insert(pos, std::make_pair(entry.first, entry.second));
else if (pos==vect.end())
//vect.insert(pos, std::make_pair(entry.first, entry.second)); //wanted to check if there's a differance between insert and push_back
vect.push_back(std::make_pair(entry.first, entry.second));
Team
类仅包含 3 个公共 int
值(points
、goalsTaken
和 goalsGiven
)、构造函数和析构函数。
对的向量称为teamOrdered
,我使用以下方法打印:
for (const auto & team : teamOrdered)
std::cout<<team.first<<" "<<team.second.points<<" "<<team.second.goalsScored<<" "<<team.second.goalsTaken<<std::endl;
【问题讨论】:
将所有内容推送到vector
。带有自定义比较器的调用 std::sort
。在您当前的代码中,当您 insert
进入向量时,您可能想要打破该内部循环。您可以从函数头中的pair
和map
中删除class
。您还需要通过引用传入vector
,否则函数内部对其进行的任何更改都将丢失。
问题是您将vector
按值带入此函数。当函数返回时,向量就消失了。如果你像orderTeams(output, input)
一样调用它,那意味着你将output
复制到函数参数vect
中,函数修改并销毁vect
,最后output
什么都没有发生。签名可能应该是void orderTeams(std::vector<...> &out, std::map<...> const &in)
,或者可能只是std::vector<...> orderTeams(std::map<...> const &in)
。 (将const
添加到map
,因为它看起来是正确的。)
orderTeams 获取了向量的副本,所以它的所有更改都会丢失,这是故意的吗?
OMGtechy 所说的。什么都不会打印,因为您将向量按值传递给函数:它将传递给函数(参数)的向量复制到一个新的局部向量(参数)中,然后在函数内部修改这个新向量,然后这个新向量退出范围,它永远不会修改您传递给函数的向量。您要么需要通过引用传递向量,要么返回排序后的向量。
@OP -- 如果您来自使用 Java 或类似对象的引用的语言,C++ 不能以这种方式工作(默认情况下)。 C++ 具有值语义,除非您指定传递引用,否则所有内容都将按值传递(或复制)。
【参考方案1】:
您的代码中存在一些问题。首先,您根本没有输出的原因是因为 vector
是按值传递的;因此,函数内部对vect
的任何更改都将丢失。您想通过引用传递它。您也可以通过const
参考传递地图,因为您不需要更改地图。
最重要的是,您的排序方法实际上不起作用。考虑内部 for 循环的条件,pos != vect.end()
;但是,您有一个else if
,即pos == vect.end()
,这根本不可能。此外,即使在添加元素之后,您仍会继续尝试将其添加到 vect
,并使用可能无效的迭代器(插入 vector
可能会导致迭代器无效)。
这是您的代码的一个工作示例:
void Championship::orderTeams(std::vector<std::pair<std::string, Team>> &vect, const std::map<std::string, Team>& map)
for (auto const& entry : map)
if (vect.empty()) //check if vector is empty and add the first pair
vect.push_back(std::make_pair(entry.first, entry.second));
continue;
bool added = false;
for (auto pos = vect.begin(); pos != vect.end(); ++pos)
if(entry.second.points > pos->second.points)
vect.insert(pos, std::make_pair(entry.first, entry.second));
added = true;
break;
if (!added)
vect.push_back(std::make_pair(entry.first, entry.second));
这也可以简化,使用来自algorithm
标头的std::sort
,而不是接受向量,您可以返回一个。
std::vector<std::pair<std::string, Team>> orderTeams2( const std::map<std::string, Team>& map)
std::vector<std::pair<std::string, Team>> vect = map.begin(), map.end() ;
std::sort( vect.begin(), vect.end(), []( auto &left, auto &right )
return left.second.points > right.second.points;
);
return vect;
【讨论】:
【参考方案2】:正如其他人所指出的那样,由于您按值传递向量,因此没有任何打印结果。通过引用传递它或返回向量。
此外,您可以使用std::sort
和谓词进行排序。这是一个可行的解决方案:
#include <algorithm>
#include <iostream>
#include <map>
#include <vector>
class Team
public:
int points;
int goalsTaken;
int goalsGiven;
;
void orderTeams(std::vector<std::pair<std::string, class Team> >& vect, std::map<std::string, class Team>& map)
for(auto currentIterator = map.begin(); currentIterator != map.end(); ++currentIterator)
vect.emplace_back(currentIterator->first, currentIterator->second);
std::sort(vect.begin(), vect.end(),
[](const std::pair<std::string, class Team>& item1, const std::pair<std::string, class Team>& item2) -> bool return item1.second.points > item2.second.points; );
int main()
std::vector< std::pair<std::string, class Team>> teamOrdered;
std::map<std::string, class Team> map;
map.emplace(std::string("4"), Team 4, 4, 4 );
map.emplace(std::string("2"), Team 2, 2, 2);
map.emplace(std::string("1"), Team 1, 1, 1 );
map.emplace(std::string("3"), Team 3, 3, 3);
orderTeams(teamOrdered, map);
for(const auto& team : teamOrdered)
std::cout << team.first << " " << team.second.points << " " << team.second.goalsGiven << " " << team.second.goalsTaken << std::endl;
【讨论】:
您的sort
与 OP 最初的顺序相反(从大到小)
已修复。谢谢。以上是关于将 std::map 转换为有序的 std::vector的主要内容,如果未能解决你的问题,请参考以下文章
将 JNI -> jobject(基本上是映射和/或 java 文件中的映射)转换为 std::map(c++)