Is it the optimal way of using std::sort()?

Viewed 146

I have a vector with 5 words in it used multiple times, what i want is to achieve this order of words: "a, zawodowe, wyzsze, podstawowe, bez wyksztalcenia" So i wrote this code, and i wonder if its the optimal way of using sort, or maybe one of the if conditions can be skipped

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;


int main()
{
   std::vector<std::string> v = {"wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia",
                                  "wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia",
                                  "wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia",
                                  "wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia", "a" };

//return a>b daje:    zawodowe, wyzsze, podstawowe, bez wyksztalcenia, a
    std::sort(v.begin(), v.end(), [](std::string a, std::string b){
        if(a == "zawodowe" && b == "a") return false;
        if(a == "a" && b == "zawodowe") return true;
        if(a == "wyzsze" && b == "a") return false;
        if(a == "podstawowe" && b == "a") return false;
        if(a == "bez wyksztalcenia" && b == "a") return false;
        return a>b;

    });

    for (std::string i: v) {
        std::cout << i << std::endl;
    }
}
2 Answers

This should be sufficient:

[](std::string a, std::string b){
        if(b == "a") return false;
        if(a == "a") return true;
        return a>b;
}

Alan's answer works when the set of words is almost alphabetical, with one value moved to an end of the sequence. For a more general approach, we need a mapping from the words to something that sorts in the order we want. Small integers are the obvious choice:

#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>

int main()
{
    std::vector<std::string> v = {"wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia",
                                  "wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia",
                                  "wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia",
                                  "wyzsze", "podstawowe", "zawodowe","podstawowe",
                                  "zawodowe", "bez wyksztalcenia", "zawodowe", "zawodowe", "wyzsze",
                                  "zawodowe", "zawodowe", "wyzsze", "podstawowe", "bez wyksztalcenia", "a" };


    auto const by_weight = [](std::string& a, std::string& b)
                           {
                               static const std::map<std::string, int> weight
                                   = {{"a", 1},
                                      {"zawodowe", 2},
                                      {"wyzsze", 3},
                                      {"podstawowe", 4},
                                      {"bez wyksztalcenia", 5}};
                               return weight.at(a) < weight.at(b);
                           };
    std::sort(v.begin(), v.end(), by_weight);

    for (auto const& i: v) {
        std::cout << i << '\n';
    }
}

Other things I fixed in passing:

  • Don't using namespace std.
  • Do include <iostream> and <string> before using them.
  • Pass strings by const reference, rather than by value.
  • Use const reference when iterating using for.
  • Prefer '\n' to std::endl when there's no need for the implied flush.
Related