¿Cómo puedo crear mi propio comparador para un mapa?


typedef map<string, string> myMap;

Al insertar un nuevo par a myMap, utilizará la clave string para comparar por su propio comparador de cadenas. ¿Es posible anular ese comparador? Por ejemplo, me gustaría comparar la clave string por su longitud, no por el alfabeto. ¿O hay alguna otra forma de ordenar el mapa?

Author: Tas, 2011-04-20

3 answers

std::map toma hasta cuatro argumentos de tipo de plantilla, el tercero es un comparador. Por ejemplo:

struct cmpByStringLength {
    bool operator()(const std::string& a, const std::string& b) const {
        return a.length() < b.length();
    }
};

// ...
std::map<std::string, std::string, cmpByStringLength> myMap;

Alternativamente, también puede pasar un comparador a maps constructor .

Tenga en cuenta, sin embargo, que al comparar por longitud solo puede tener una cadena de cada longitud en el mapa como clave.

 99
Author: Georg Fritzsche,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 16:09:18

Sí, el parámetro 3rd template en map especifica el comparador, que es un predicado binario. Ejemplo:

struct ByLength : public std::binary_function<string, string, bool>
{
    bool operator()(const string& lhs, const string& rhs) const
    {
        return lhs.length() < rhs.length();
    }
};

int main()
{
    typedef map<string, string, ByLength> lenmap;
    lenmap mymap;

    mymap["one"] = "one";
    mymap["a"] = "a";
    mymap["fewbahr"] = "foobar";

    for( lenmap::const_iterator it = mymap.begin(), end = mymap.end(); it != end; ++it )
        cout << it->first << "\n";
}
 10
Author: John Dibling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-20 16:11:32

Desde C++11 , también puede usar una expresión lambda en lugar de definir una estructura de comparación:

auto comp = [](const string& a, const string& b) { return a.length() < b.length(); };
map<string, string, decltype(comp)> my_map(comp);

my_map["1"]      = "a";
my_map["three"]  = "b";
my_map["two"]    = "c";
my_map["fouuur"] = "d";

for(auto const &kv : my_map)
    cout << kv.first << endl;

Salida:

1
dos
tres
fouuur

Me gustaría repetir la nota final de la respuesta de Georg: Al comparar por longitud solo se puede tener una cadena de cada longitud en el mapa como clave.

Código en Ideone

 6
Author: honk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-07 14:58:49