2010-06-28 11 views
170

Jaki jest najlepszy sposób określenia, czy mapa STL zawiera wartość dla danego klucza?Ustal, czy mapa zawiera wartość klucza?

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

} 

Badanie to w debugger, wygląda iter jest tylko dane na śmieci.

Gdybym odkomentowaniu tę linię:

Bar b2 = m[2] 

Debuger pokazuje, że b2 jest {i = 0}. (Zgaduję, że oznacza to, że użycie niezdefiniowanego indeksu zwróci strukturę ze wszystkimi pustymi/niezainicjowanymi wartościami?)

Żadna z tych metod nie jest tak dobra. To, co naprawdę chciałbym, to taki interfejs:

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

Czy istnieje coś takiego?

+1

możliwe duplikat [Jak się dowiedzieć, czy dany klucz istnieje w C++ std :: map] (http://stackoverflow.com/questions/1939953/how-to-find-if-a-given -key-exists-in-ac-stdmap) – OrangeDog

Odpowiedz

188

Czy istnieje coś takiego?

Nr z klasą stl map użyć ::find() przeszukać mapę i porównać zwrócony iterator do std::map::end()

tak

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

Oczywiście można napisać własny getValue() rutynowych jeśli chcesz (również w C++, nie ma powodu, aby korzystać z out), ale podejrzewam, że gdy pojawi się powiesić przy użyciu std::map::find(), nie będziesz chciał tracić czasu.

także kod jest nieco źle:

m.find('2'); będzie przeszukiwać mapę na keyvalue że jest '2'. IIRC kompilator C++ domyślnie konwertuje "2" na int, co powoduje, że wartość liczbowa dla kodu ASCII dla "2" nie jest tym, czego potrzebujesz.

Od swojej KeyType w tym przykładzie jest int chcesz szukać tak: m.find(2);

+6

Tak, dobry połów z błędem "2'' v.' 2'. –

+2

odpowiedzi To brzmi znacznie lepiej: http://stackoverflow.com/a/11765524/496223 Jak więc – dynamic

+4

? 'find' oznacza intencję znacznie lepszą niż' count'. Co więcej, 'count' nie zwraca pozycji. Jeśli czytasz pytanie OP, on chce sprawdzić istnienie, * i * zwrócić element. 'find' to robi. 'count' nie. – Alan

4

Sprawdź wartość zwracaną find na end.

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

amap.find powraca amap::end gdy nie znajdujesz tego, czego szukasz - masz za zadanie sprawdzić, że.

37

już istnieje to nie tylko ze odnaleźć w tym dokładnej składni.

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

Jeśli chcesz uzyskać dostęp do wartości, jeśli istnieje, można zrobić:

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

z C++ 0x i auto, składnia jest prostsze:

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

I zalecamy przyzwyczaić się do niego, zamiast próbować wymyślić nowy mechanizm, aby go uprościć. Możesz zmniejszyć trochę kodu, ale rozważ koszt wykonania tego. Teraz wprowadziłeś nową funkcję, którą ludzie znający C++ nie będą w stanie rozpoznać.

Jeśli chcesz zaimplementować to w każdym razie mimo tych ostrzeżeń, a następnie:

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

Można utworzyć funkcję getValue z następującego kodu:

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

Wierzę, że wiersz 6 powinien być "out = foundIter-> second' – Dithermaster

+0

Naprawiłem odpowiedź Kipa, aby poprawnie pokazać' out = foundIter-> second' zamiast 'out = * foundIter' – netjeff

240

Dopóki mapa jest nie jest multimapą, jednym z najbardziej eleganckich sposobów byłoby użycie metody liczenia. unt będzie 1, jeśli element jest rzeczywiście obecny na mapie.

+10

Czy to nie sprawdzi * wszystkie * klucze nawet jeśli już to znalazł? To może szybko stać się kosztownym ... – mmdanziger

+20

Liczy tylko więcej niż jeden klucz, jeśli jest używany w multimapie. –

+0

Fantastyczne. Nigdy nie przyszło mi do głowy, że mogę to zrobić. Dzięki. –

0

Jeśli chcesz określić, czy klucz jest nie na mapie, czy nie, można użyć find() lub count() funkcji członka na mapie. Funkcja wyszukiwania, która jest tutaj użyta w przykładzie, zwraca iterator do elementu lub mapy :: koniec w przeciwnym razie. W przypadku zliczenia, liczba zwraca 1, jeśli znaleziono, w przeciwnym razie zwraca zero (lub w inny sposób).

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

Do optymalnego rozwiązania można użyć funkcji Boost multindex. następujące rozwiązanie nie jest bardzo najlepszym rozwiązaniem, ale może być przydatna w kilku przypadkach, gdy użytkownik przypisuje domyślną wartość 0 lub NULL jak przy inicjalizacji i chcesz sprawdzić, czy wartość została zmodyfikowana.

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; 
} 
Powiązane problemy