2010-06-28 20 views
170

Qual è il modo migliore per determinare se una mappa STL contiene un valore per una determinata chiave?Determina se la mappa contiene un valore per una chiave?

#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; 

} 

Esaminando questo in un debugger, sembra iter soli caratteri privi di significato.

Se io Decommentare questa riga:

Bar b2 = m[2] 

Il debugger mostra che b2 è {i = 0}. (Sto indovinando significa che l'utilizzo di un indice indefinito restituirà una struttura con tutti i valori vuoti/non inizializzati?)

Nessuno di questi metodi è così grande. Quello che mi piacerebbe davvero è un'interfaccia come questa:

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

Esiste qualcosa in questo senso?

+1

possibile duplicato di [Come trovare se una data chiave esiste in uno std :: map C++] (http://stackoverflow.com/questions/1939953/how-to-find-if-a-given -key-exists-in-ac-stdmap) – OrangeDog

risposta

188

Esiste qualcosa in questo senso?

No. Con la classe STL mappa, si utilizza ::find() per cercare la mappa, e confrontare l'iteratore restituito al std::map::end()

così

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

Ovviamente è possibile scrivere il proprio getValue() di routine se vuoi (anche in C++, non c'è motivo di usare out), ma sospetterei che una volta che avrai capito di usare std::map::find() non vorrai perdere tempo.

anche il codice è leggermente sbagliato:

m.find('2'); cercherà la mappa per una keyvalue che è '2'. IIRC il compilatore C++ convertirà implicitamente '2' in un int, che si traduce nel valore numerico per il codice ASCII per '2' che non è quello che vuoi.

Dal momento che il KeyType in questo esempio è int si desidera ricercare in questo modo: m.find(2);

+6

Sì, buona cattura con l'errore ''2'' v.' 2'. –

+2

Questa risposta suona molto meglio: http://stackoverflow.com/a/11765524/496223 – dynamic

+4

In che modo? 'find' indica l'intento molto meglio di" count ". Inoltre, 'count' non restituisce l'oggetto. Se leggi la domanda dell'OP, vuole verificare l'esistenza, * e * restituire l'elemento. 'find' lo fa. 'count' non lo fa. – Alan

4

Verificare il valore di ritorno di find rispetto a end.

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

amap.find rendimenti amap::end quando non trovare quello che stai cercando - si suppone di verificare la presenza di questo.

37

Esiste già con solo trovare non in quella sintassi esatta.

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

Se si desidera accedere al valore se esiste, si può fare:

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

Con C++ 0x e auto, la sintassi è semplice:

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

I raccomandare di abituarsi ad esso piuttosto che cercare di trovare un nuovo meccanismo per semplificarlo. Potresti essere in grado di ridurre un po 'di codice, ma considera il costo di farlo. Ora hai introdotto una nuova funzione che le persone che hanno familiarità con C++ non saranno in grado di riconoscere.

Se si desidera implementare questo comunque a dispetto di questi avvertimenti, poi:

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; 
} 
1

È possibile creare la funzione getValue con il seguente codice:

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; 
} 
+0

Credo che la linea 6 debba essere 'out = foundIter-> second' – Dithermaster

+0

Ho corretto la risposta di Kip per mostrare correttamente' out = foundIter-> second' piuttosto che 'out = * foundIter' – netjeff

240

Finché la mappa è non un multimap, uno dei modi più eleganti sarebbe quello di utilizzare il metodo di conteggio

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

Il co unt sarebbe 1 se l'elemento è effettivamente presente nella mappa.

+10

Non verificherà * tutti * i tasti anche se ne ha già trovato uno? Questo può diventare costoso velocemente ... – mmdanziger

+20

Conterà solo più di una chiave se usata su una multimap. –

+0

Fantastico. Non ho mai pensato che potevo farlo. Grazie. –

0

Se si desidera determinare se una chiave è presente o meno nella mappa, è possibile utilizzare la funzione membro della mappa find() o count(). La funzione di ricerca utilizzata qui nell'esempio restituisce l'iteratore all'elemento o alla mappa :: end altrimenti. In caso di conteggio il conteggio restituisce 1 se trovato, altrimenti restituisce zero (o altrimenti).

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

Boost multindex può essere utilizzato per soluzione adeguata. La seguente soluzione non è l'opzione migliore ma potrebbe essere utile in alcuni casi in cui l'utente sta assegnando il valore predefinito come 0 o NULL all'inizializzazione e desidera verificare se il valore è stato modificato.

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; 
} 
Problemi correlati