xampierre
xampierre

Reputation: 103

Transforming std::map into ordered std::vector

I have a std::map that stores a string and a class and i want to make an ordered vector based on the value of a class attribute. However, when i iterate over the vector, nothing prints. My code so far is this and the compiler sees no errors:

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));
            }
        }
    }
}

Class Team only contains 3 public int values( points, goalsTaken and goalsGiven), constructor and distructor.

The vector of pairs is called teamOrdered and i printed using:

    for (const auto & team : teamOrdered){
        std::cout<<team.first<<" "<<team.second.points<<" "<<team.second.goalsScored<<" "<<team.second.goalsTaken<<std::endl;
    }

Upvotes: 0

Views: 110

Answers (2)

KulaGGin
KulaGGin

Reputation: 1252

As pointed by other people, nothing prints for you because you passed vector by value. Pass it by reference or return the vector.

Also, you can sort using std::sort and a predicate. Here's a working solution:

#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;
    }
}

Upvotes: 1

ChrisMM
ChrisMM

Reputation: 10097

There's a few issues in your code. Firstly, the reason why you get no output at all, is because the vector is passed in by value; therefore, any changes to vect inside the function are lost. You want to pass it in by reference instead. You can also pass the map in by const reference, since you don't need to change the map.

On top of that, your sort method doesn't actually work. Consider the inner for-loop's condition, pos != vect.end(); however, you have an else if which is pos == vect.end(), which is simply impossible. Further, even after the element is added, you keep attempting to add it to vect, with a potentially invalid iterator (inserting into a vector may cause iterator invalidity).

Here's a working example of you code:

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));
        }
    }
}

This can also be simplified, using std::sort from the algorithm header, and instead of taking in a vector, you can return one instead.

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;
}

Upvotes: 3

Related Questions