web-dev-qa-db-fra.com

Vérification de la valeur dans std :: map - C++

Je sais que la méthode find trouve la clé fournie dans std :: map et renvoie un itérateur à l'élément. Est-il possible de trouver la valeur et d'obtenir un itérateur pour l'élément? Ce que je dois faire est de vérifier la valeur spécifiée dans std :: map. J'ai fait cela en bouclant tous les éléments de la carte et en comparant. Mais je voulais savoir s'il y avait une meilleure approche pour cela.

Voici ce que j'ai écrit

bool ContainsValue(Type_ value)
{
    bool found = false;
    Map_::iterator it = internalMap.begin(); // internalMap is std::map
    while(it != internalMap.end())
    {
        found = (it->second == value);
        if(found)
            break;
        ++it;
    }
    return found;
}

Modifier

Que diriez-vous d'utiliser une autre carte en interne qui stocke la valeur, la combinaison de touches. Donc je peux appeler trouver dessus? Est-ce que find () dans std :: map effectue une recherche séquentielle?

Merci

30
Navaneeth K N

Vous pouvez utiliser boost :: multi_index pour créer une carte bidirectionnelle -. Vous pouvez utiliser l'une ou l'autre valeur de la paire comme clé pour effectuer une recherche rapide.

20
Mark Ransom

Si vous avez accès à l'excellente bibliothèque boost , vous devriez utiliser boost :: multi_index pour créer une carte bidirectionnelle , comme le dit Mark. Contrairement à std :: map, cela vous permet de rechercher la clé ou la valeur.

Si vous ne disposez que de la STL, le code suivant fera l'affaire (basé sur un modèle conçu pour fonctionner avec tout type de carte où mapped_type prend en charge l'opérateur ==):

#include <map>
#include <string>
#include <algorithm>
#include <iostream>
#include <cassert>

template<class T>
struct map_data_compare : public std::binary_function<typename T::value_type, 
                                                      typename T::mapped_type, 
                                                      bool>
{
public:
    bool operator() (typename T::value_type &pair, 
                     typename T::mapped_type i) const
    {
        return pair.second == i;
    }
};


int main()
{
    typedef std::map<std::string, int> mapType;

    mapType map;

    map["a"] = 1;
    map["b"] = 2;
    map["c"] = 3;
    map["d"] = 4;
    map["e"] = 5;

    const int value = 3;

    std::map<std::string, int>::iterator it = std::find_if( map.begin(), map.end(), std::bind2nd(map_data_compare<mapType>(), value) );

    if ( it != map.end() )
    {
        assert( value == it->second);
        std::cout << "Found index:" << it->first << " for value:" << it->second << std::endl;
    }
    else
    {
        std::cout << "Did not find index for value:" << value << std::endl;
    }
}
16
CodeBuddy

Que diriez-vous d'utiliser une autre carte en interne qui stocke la valeur, la combinaison de touches. Donc je peux appeler trouver dessus?

Oui: conservez deux cartes, l’une utilisant un type de clé et l’autre utilisant l’autre.

Est-ce que find () dans std :: map effectue une recherche séquentielle?

Non, il s'agit d'une recherche binaire dans un arbre trié: sa vitesse est O (log (n)).

15
ChrisW

Recherchez dans les cartes bidirectionnelles de boost: http://www.boost.org/doc/libs/1_38_0/libs/bimap/doc/html/index.html

Cela permet aux deux valeurs d'agir comme une clé.

Sinon, l'itération est la voie à suivre.

6
Evan Teran

essayez cette fonction:

template <class Map, class Val> typename Map::const_iterator MapSearchByValue(const Map & SearchMap, const Val & SearchVal)
{
    Map::const_iterator iRet = SearchMap.end();
    for (Map::const_iterator iTer = SearchMap.begin(); iTer != SearchMap.end(); iTer ++)
    {
        if (iTer->second == SearchVal)
        {
            iRet = iTer;
            break;
        }
    }
    return iRet;
}

je pense que c'est utile

4
Mitch

Non, vous devez parcourir std :: map et vérifier toutes les valeurs manuellement. En fonction de ce que vous voulez faire, vous pouvez insérer std :: map dans une classe simple qui met également en cache toutes les valeurs insérées dans la carte dans un objet facilement consultable et ne permettant pas les doublons, comme un objet std ::ensemble. N'héritez pas de std :: map (il n'a pas de destructeur virtuel!), Mais enveloppez-le pour pouvoir faire quelque chose comme ça:

WrappedMap my_map< std::string, double >;
my_map[ "key" ] = 99.0;
std::set< double > values = my_map.values(); // should give back a set with only 99.0 in it

Une autre solution consiste à utiliser la carte bidirectionnelle Boost, que vous trouverez facilement dans les messages ci-dessous ou dans Google.

Cela dépend vraiment de ce que vous voulez faire, de la fréquence à laquelle vous voulez le faire et de la difficulté de faire rouler votre propre petite classe de wrapper par rapport à l'installation et à l'utilisation de Boost. J'aime Boost, alors c’est un bon moyen d’aller, mais il ya quelque chose de sympa et complet dans la création de votre propre cours d’emballage. Vous avez l’avantage de comprendre directement la complexité des opérations et vous n’avez peut-être pas besoin du mappage inverse complet des valeurs => clés fourni par la mappe bidirectionnelle Boost.

2
James Thompson

Ce que vous demandez, c’est précisément ce que std :: find fait (pas la fonction membre)

template< class InputIt, class T >
InputIt find( InputIt first, InputIt last, const T& value );
1
AKludges

J'ajoute cette réponse, si quelqu'un vient ici et cherche c ++ 11 et plus ..

    //DECLARE A MAP
    std::map<int, int> testmap;

    //SAMPLE DATA
    testmap.insert(std::make_pair(1, 10));
    testmap.insert(std::make_pair(2, 20));
    testmap.insert(std::make_pair(3, 30));
    testmap.insert(std::make_pair(4, 20));

    //ELEMENTS WITH VALUE TO BE FOUND
    int value = 20;

    //RESULTS
    std::map<int, int> valuesMatching;

    //ONE STEP TO FIND ALL MATCHING MAP ELEMENTS
    std::copy_if(testmap.begin(), testmap.end(), std::inserter(valuesMatching, valuesMatching.end()), [value](const auto& v) {return v.second == value; });
0
Naidu

Pas une très bonne option, mais pourrait être utile dans quelques cas où l'utilisateur attribue une valeur par défaut telle que 0 ou NULL à l'initialisation 

Ex.
< int , string >
< string , int > 
< string , string > 

consider < string , string >
mymap["1st"]="first";
mymap["second"]="";
for (std::map<string,string>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
{
       if ( it->second =="" ) 
            continue;
}
0
user2761565