简体   繁体   中英

why it isn't possible to sort a std::map directly using std::sort based upon its value field

I've already seen lot of solutions for sorting a std::map based on its value. But I want to know why it's not possible to sort it directly using std::sort like the code I've written.

#include <iostream>
#include <map>
#include <algorithm>


void print_values(const std::map<size_t, size_t>& map_data) {
    for(const auto& my_pair : map_data)
        std::cout << my_pair.first << " : " << my_pair.second << "\n";
    std::cout << std::endl;
}

bool compare(const std::pair<size_t, size_t>& a, const std::pair<size_t, size_t>& b) {
    return a.second > b.second;
}

int32_t main(int32_t argc, char* argv[]) {
    std::map<size_t, size_t> coins_count;
    coins_count.insert(std::make_pair(1, 2));
    coins_count.insert(std::make_pair(2, 3));
    coins_count.insert(std::make_pair(3, 4));
    coins_count.insert(std::make_pair(4, 2));
    coins_count.insert(std::make_pair(5, 3));
    coins_count.insert(std::make_pair(6, 1));
    coins_count.insert(std::make_pair(7, 2));
    
    print_values(coins_count);
    
    std::sort(coins_count.begin(), coins_count.end(), compare);
    
    print_values(coins_count);

    return EXIT_SUCCESS;
}

std::map is implemented as some flavor of binary search tree sorted by key. That means that a std::map must always be sorted by key, using the comparison function defined for the map at construction time, for element lookup to function properly.

The map itself is always sorted by key. So you can only sort some other thing, that could refer to map elements.

You could sort an array of map iterators:

std::vector<decltype(coins_count)::iterator> vec;
for (auto i = coins_count.begin(), end = coins_count.end(); i != end; ++i) {
    vec.push_back(i);
}
std::sort(vec.begin(), vec.end(),
    [](auto& a, auto& b) { return a->second < b->second; }
);    
for(auto&& i : vec) {
    std::cout << i->first << " : " << i->second << "\n";
}

Alternatively you could sort an array of map keys:

std::vector<decltype(coins_count)::key_type> vec;
for(auto&& i : coins_count) {
    vec.push_back(i.first);
}
std::sort(vec.begin(), vec.end(),
    [&coins_count](auto& a, auto& b) {
        return coins_count.at(a) < coins_count.at(b);
    }
);
for(auto&& i : vec) {
    std::cout << i << " : " << coins_count.at(i) << "\n";
}

Code will output:

6 : 1
1 : 2
4 : 2
7 : 2
2 : 3
5 : 3
3 : 4

The elements of a map are always maintained in a sorted manner, by definition.

You can define this ordering yourself using a template argument, but you cannot manually change the order of elements yourself with std::sort (and this call will fail even if no elements would have been swapped).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM