web-dev-qa-db-fra.com

Recherche inversée de carte

J'ai une carte 1 à 1. Quelle est la meilleure façon de trouver des clés à partir de valeurs,

c'est à dire.

Par exemple, si la carte est la suivante

VALEUR CLÉ

a    1
b    2
c    3 
d    4

Je veux pouvoir trouver que la clé correspondant à 3 est C.

Merci!

40
user620189

Vous ne pouvez pas faire grand-chose à ce sujet. Vous avez des options pour travailler avec deux cartes, utiliser une carte à touches multiples comme celle de la bibliothèque Boost Multi-Index , ou faire une recherche linéaire.

MISE À JOUR: La solution la plus légère prête à l'emploi semble être Boost.Bimap , qui signifie carte bidirectionnelle.

30
user405725

Disons que vous avez une carte<X,Y>. Construisez une deuxième structure, peut-être une map<Y*,X*,Deref> qui permet la recherche inversée mais évite de doubler la surcharge de stockage, car, à l'aide de pointeurs, il n'est pas nécessaire de stocker chaque X et Y deux fois. La deuxième structure a simplement des pointeurs dans la première.

11
Amit

Le moyen le plus direct serait de maintenir une carte parallèle où les valeurs et les clés sont inversées (puisque la relation est une à une).

8
MAK

Une autre solution serait d'utiliser (la moins connue?) Boost.Bimap :

Boost.Bimap est une bibliothèque de cartes bidirectionnelles pour C++. Avec Boost.Bimap, vous pouvez créer des conteneurs associatifs dans lesquels les deux types peuvent être utilisés comme clé. UNE bimap<X,Y> peut être considéré comme une combinaison d'un std::map<X,Y> et un std::map<Y,X>. La courbe d'apprentissage du bimap est presque plate si vous savez utiliser des conteneurs standard. Beaucoup d'efforts ont été déployés pour cartographier le schéma de dénomination de la STL dans Boost.Bimap. La bibliothèque est conçue pour correspondre aux conteneurs STL courants.

6

À moins que la carte soit immense ou que vous ayez une autre façon de savoir que la recherche linéaire est trop lente, je commencerais par la recherche linéaire:

#include <iostream>
using std::cout;

#include <map>
using std::map;

#include <algorithm>
using std::find_if;

#include <boost/assign/list_of.hpp>
using boost::assign::map_list_of;

typedef map<char, int> Map;
typedef Map::key_type Key;
typedef Map::value_type Pair;
typedef Map::mapped_type Value;


struct Finder {
    const Value v;
    Finder(const Value& v) : v(v) {}
    bool operator()(const Pair& p) {
        return p.second == v;
    }
};

Map m = map_list_of('a', 1)('b', 2)('c', 3)('d', 4)('e', 5);

int main() {
    Pair v = *find_if(m.begin(), m.end(), Finder(3));
    cout << v.second << "->" << v.first << "\n";
}
4
Robᵩ

Une variante de la réponse de @ Robᵩ ci-dessus qui utilise un lambda:

map<char, int> m = {{'a', 1}, {'b', 2}, {'c', 3}, {'d', 4}, {'e', 5}};

int findVal = 3;
auto it = find_if(m.begin(), m.end(), [findVal](const Pair & p) {
    return p.second == findVal;
});
if (it == m.end()) {
    /*value not found*/
    cout << "*value not found*";
}
else {
    Pair v = *it;
    cout << v.second << "->" << v.first << "\n";
}

(merci à @Nawaz pour sa contribution ici: https://stackoverflow.com/a/19828596/1650814 )

3
WXB13

Je sais que c'est une très vieille question, mais cet article de codeproject ( http://www.codeproject.com/Articles/3016/An-STL-like-bidirectional-map ) est un assez bon exemple de une carte bidirectionnelle.

Voici un exemple de programme qui montre à quel point c'est simple:

 #pragma warning(disable:4503)

    #include "bimap.h"
    #include <iostream>
    #include <string>

    using codeproject::bimap;

    int main(void)
    {
      bimap<int,std::string> bm;

      bm[1]="Monday";
      bm[2]="Tuesday";
      bm[3]="Wednesday";
      bm[4]="Thursday";
      bm[5]="Friday";
      bm[6]="Saturday";
      bm[7]="Sunday";

      std::cout<<"Thursday occupies place #"<<bm["Thursday"]<<
                 " in the week (european style)"<<std::endl;
      return 0;
    }
2
Yannick Lange

Donné un std::map des clés aux valeurs, la fonction suivante renverra une table de recherche inversée, un std::map des valeurs aux clés.

    /// Given a map from keys to values, creates a new map from values to keys 
    template<typename K, typename V>
    static map<V, K> reverse_map(const map<K, V>& m) {
        map<V, K> r;
        for (const auto& kv : m)
            r[kv.second] = kv.first;
        return r;
    }
1
cdiggins