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

10,698

Solution 1

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.

Solution 2

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 Sergey, I'm assuming 32-bit integers for the sake of clarity. Please adapt the code to your needs.

Code on Ideone

Solution 3

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
}
Share:
10,698
rsk82
Author by

rsk82

Updated on July 16, 2022

Comments

  • rsk82
    rsk82 almost 2 years

    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.