将 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 值(pointsgoalsTakengoalsGiven)、构造函数和析构函数。

对的向量称为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 进入向量时,您可能想要打破该内部循环。您可以从函数头中的pairmap 中删除class。您还需要通过引用传入vector,否则函数内部对其进行的任何更改都将丢失。 问题是您将vector 按值带入此函数。当函数返回时,向量就消失了。如果你像orderTeams(output, input)一样调用它,那意味着你将output复制到函数参数vect中,函数修改并销毁vect,最后output什么都没有发生。签名可能应该是void orderTeams(std::vector&lt;...&gt; &amp;out, std::map&lt;...&gt; const &amp;in),或者可能只是std::vector&lt;...&gt; orderTeams(std::map&lt;...&gt; const &amp;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++)

将 C++ 类转换为 JSON

std::Map

std::map 的底层结构是啥? [关闭]

C++ std::map 和 std::unordered_map 区别 时间复杂度 适用

std::map 到 std::list 导致 SIGSEGV