简体   繁体   中英

How can I declare a custom sort function on std::map declaration?

The container std::map always sorts keys based on their value. Is it possible to make it sort, for example, on the number of bits set upon declaration?

I have a function for counting set bits:

for(size_t i = 0; i < CHAR_BIT * sizeof value; ++i, value >>= 1) {
  if ((value & 1) == byteState) ++num_bits;
}

But I do not know how to apply it when declaring the map:

std::map<int, int> myMap = {
  {1,2},
  {3,4},
  //...
}

I've tried to put it as a third parameter in the declaration <int,int,decltype(countSetBits)> , but with no luck.

You need to wrap your function in a binary operator, like this:

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

int cntBits(int value) {
    int num_bits=0;
    for(size_t i = 0; i < 32 ; ++i, value >>= 1) {
        if ((value & 1) == 1) ++num_bits;
    }
    return num_bits;
}

struct cntBitsCmp {
    bool operator()(int a, int b) {
        return cntBits(a) < cntBits(b);
    }
};

Now you can use cntBitsCmp in a declaration:

std::map<int,int,cntBitsCmp> myMap= {
    {128,2},
    {3,4},
    ...
};

Here is a demo on ideone . It correctly orders 128 ahead of 3, because 3 has two bits set, while 128 has only one.

Basically this could work as you want:

bool comp(int x , int y ){
    return  __builtin_popcount(x) <  __builtin_popcount(y);
}
int main(){
    bool(*fn_pt)(int,int) = comp;
    std::map<int, int, bool(*)(int,int) > myMap (fn_pt);
    myMap[7]=11;
    myMap[8]=12;
    cout<<myMap.begin()->first<<endl;  // you get 8 instead of 7
}

Since C++11 , you can also use a lambda expression instead of defining a comparison function. If you combine this with std::bitset::count instead of using your own counting function, then the code becomes rather short:

auto comp = [](int a, int b) { return std::bitset<32>(a).count() < std::bitset<32>(b).count(); };
std::map<int, int, decltype(comp)> m(comp);

Note: Similar to the solution by dasblinkenlight, I'm assuming 32-bit integers for the sake of clarity. Please adapt the code to your needs.

Code on Ideone

When I wrapped my function in a binary operator and used it sort my map via the length of the strings (key) all was well and it worked. However, what I did not realise is that it affected the maps find() function. Instead of finding the key that is equal to the string it would instead find the key that has the same string length as the key!

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