278 votes

Déterminer si la carte contient une valeur pour une clé ?

Quelle est la meilleure façon de déterminer si une carte STL contient une valeur pour une clé donnée ?

#include <map>

using namespace std;

struct Bar
{
    int i;
};

int main()
{
    map<int, Bar> m;
    Bar b = {0};
    Bar b1 = {1};

    m[0] = b;
    m[1] = b1;

    //Bar b2 = m[2];
    map<int, Bar>::iterator iter = m.find(2);
    Bar b3 = iter->second;

}

En examinant cela dans un débogueur, on obtient ce qui suit iter n'est qu'une donnée inutile.

Si je décommente cette ligne :

Bar b2 = m[2]

Le débogueur montre que b2 es {i = 0} . (Je suppose que cela signifie que l'utilisation d'un index non défini renverra une structure avec toutes les valeurs vides/non initialisées).

Aucune de ces méthodes n'est très efficace. Ce que j'aimerais vraiment, c'est une interface comme celle-ci :

bool getValue(int key, Bar& out)
{
    if (map contains value for key)
    {
        out = map[key];
        return true;
    }
    return false;
}

Existe-t-il quelque chose de ce type ?

2 votes

369voto

pconnell Points 756

Tant que la carte n'est pas une carte multiple, l'une des méthodes les plus élégantes consiste à utiliser la méthode de comptage

if (m.count(key))
    // key exists

Le compte sera de 1 si l'élément est effectivement présent dans la carte.

28 votes

Ce contrôle ne sera-t-il pas tous les clés même s'il en a déjà trouvé une ? Cela peut vite coûter cher...

38 votes

Il ne comptera plus qu'une seule touche s'il est utilisé sur une carte multiple.

0 votes

Fantastique. Il ne m'était jamais venu à l'esprit que je pouvais faire cela. Je vous remercie.

300voto

Alan Points 21367

Existe-t-il quelque chose de ce type ?

Non. Avec la classe de carte stl, vous utilisez ::find() pour rechercher la carte, et comparer l'itérateur retourné à std::map::end()

donc

map<int,Bar>::iterator it = m.find('2');
Bar b3;
if(it != m.end())
{
   //element found;
   b3 = it->second;
}

Il est évident que vous pouvez écrire votre propre getValue() si vous le souhaitez (même en C++, il n'y a aucune raison d'utiliser la routine out ), mais je pense qu'une fois que vous aurez pris l'habitude d'utiliser la fonction std::map::find() vous ne voudrez pas perdre votre temps.

Votre code est également légèrement erroné :

m.find('2'); recherchera dans la carte une valeur clé qui est '2' . Le compilateur C++ convertit implicitement "2" en "int", ce qui donne la valeur numérique du code ASCII de "2", ce qui n'est pas ce que vous voulez.

Puisque votre type de clé dans cet exemple est int vous souhaitez effectuer une recherche de ce type : m.find(2);

7 votes

Comment cela se fait-il ? find indique l'intention bien mieux que count ne. Plus d'informations, count ne renvoie pas l'objet. Si vous lisez la question de l'OP, il veut vérifier l'existence du produit, y renvoie l'élément. find le fait. count ne le fait pas.

1 votes

If (m.count(key)) b3 = m[key] ; //or whatever

99 votes

J'ai toujours été curieux de savoir quel genre d'herbe fumaient les personnes qui ont conçu l'API stl.

54voto

stinky472 Points 4864

Cela existe déjà avec find, mais pas dans cette syntaxe exacte.

if (m.find(2) == m.end() )
{
    // key 2 doesn't exist
}

Si vous voulez accéder à la valeur si elle existe, vous pouvez le faire :

map<int, Bar>::iterator iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

Avec C++0x et auto, la syntaxe est plus simple :

auto iter = m.find(2);
if (iter != m.end() )
{
    // key 2 exists, do something with iter->second (the value)
}

Je vous recommande de vous y habituer plutôt que d'essayer de trouver un nouveau mécanisme pour le simplifier. Vous pourrez peut-être réduire un peu le code, mais considérez le coût de cette opération

I

template <class Key, class Value, class Comparator, class Alloc>
bool getValue(const std::map<Key, Value, Comparator, Alloc>& my_map, int key, Value& out)
{
    typename std::map<Key, Value, Comparator, Alloc>::const_iterator it = my_map.find(key);
    if (it != my_map.end() )
    {
        out = it->second;
        return true;
    }
    return false;
}

9voto

Alex Martelli Points 330805

retourne quand il ne trouve pas ce que vous recherchez--vous êtes censé pour vérifier pour cela.

4voto

JaredPar Points 333733

Vérifier la valeur de retour de find contre end .

map<int, Bar>::iterator it = m.find('2');
if ( m.end() != it ) { 
  // contains
  ...
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X