web-dev-qa-db-fra.com

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

Quel est le meilleur moyen 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, il semble que iter ne soit que des données vides.

Si je ne commente pas cette ligne:

Bar b2 = m[2]

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

Aucune de ces méthodes n'est si géniale. 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 dans ce sens?

219
Nick Heiner

Existe-t-il quelque chose dans ce sens?

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

alors

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

Vous pouvez évidemment écrire votre propre routine getValue() si vous le souhaitez (également en C++, il n’ya aucune raison d’utiliser out), mais je soupçonne qu’une fois que vous aurez appris à utiliser std::map::find(), vous ne voudrez plus gaspiller votre temps.

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

m.find('2'); recherchera sur la carte une valeur de clé égale à '2'. Le compilateur C++ IIRC convertira implicitement "2" en un entier, ce qui donne la valeur numérique pour le code ASCII pour "2", ce qui n'est pas ce que vous voulez.

Étant donné que votre type de clé dans cet exemple est int, vous souhaitez effectuer une recherche comme suit: m.find(2);

241
Alan

Tant que la carte n’est pas une carte multiple, l’un des moyens les plus élégants serait d’utiliser la méthode de comptage.

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

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

293
pconnell

Il 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 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 le faire. Vous avez maintenant introduit une nouvelle fonction que les personnes familiarisées avec C++ ne pourront pas reconnaître.

Si vous voulez quand même implémenter cela malgré ces avertissements, alors:

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;
}
50
stinky472

Je viens de remarquer qu'avec C++ 2 , nous aurons

std::map::contains( const Key& key ) const;

Cela retournera true si map contient un élément avec la clé key.

19
kebs

amap.find renvoie amap::end s'il ne trouve pas ce que vous cherchez - vous êtes censé vérifier cela.

7
Alex Martelli

Vérifiez la valeur de retour de find par rapport à end.

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

Pour résumer succinctement certaines des autres réponses:

Si vous n'utilisez pas encore C++ 20, vous pouvez écrire votre propre fonction mapContainsKey:

bool mapContainsKey(std::map<int, int>& map, int key)
{
  if (map.find(key) == map.end()) return false;
  return true;
}

Si vous souhaitez éviter de nombreuses surcharges pour map vs unordered_map et pour différents types de clé et de valeur, vous pouvez en faire une fonction template.

Si vous utilisez C++ 20 ou une version ultérieure, il y aura une fonction intégrée contains:

std::map<int, int> myMap;

// do stuff with myMap here

int key = 123;

if (myMap.contains(key))
{
  // stuff here
}
1
cdahms

Vous pouvez créer votre fonction getValue avec le code suivant:

bool getValue(const std::map<int, Bar>& input, int key, Bar& out)
{
   std::map<int, Bar>::iterator foundIter = input.find(key);
   if (foundIter != input.end())
   {
      out = foundIter->second;
      return true;
   }
   return false;
}
1
Kip Streithorst

Si vous voulez déterminer si une clé est présente ou non dans la carte, vous pouvez utiliser la fonction membre find () ou count () de la carte. La fonction find qui est utilisée ici dans l'exemple renvoie l'itérateur à element ou map :: end sinon. En cas de décompte, le décompte retourne 1 s'il est trouvé, sinon il renvoie zéro (ou sinon).

if(phone.count(key))
{ //key found
}
else
{//key not found
}

for(int i=0;i<v.size();i++){
    phoneMap::iterator itr=phone.find(v[i]);//I have used a vector in this example to check through map you cal receive a value using at() e.g: map.at(key);
    if(itr!=phone.end())
        cout<<v[i]<<"="<<itr->second<<endl;
    else
        cout<<"Not found"<<endl;
}
0
Prashant Shubham