2009-02-11 7 views
26

Ich weiß, Suche Methode findet den mitgelieferten Schlüssel in Std :: Karte und einen Iterator an das Element zurückgeben. Gibt es überhaupt einen Wert, um den Wert zu finden und einen Iterator für das Element zu erhalten? Was ich tun muss, ist den angegebenen Wert in std :: map zu überprüfen. Ich habe dies getan, indem ich alle Elemente in der Karte durchschlinge und vergleiche. Aber ich wollte wissen, ob es dafür einen besseren Ansatz gibt. HierÜberprüfung Wert existiert in einer Std :: Karte - C++

ist das, was ich geschrieben habe

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

bearbeiten

Wie wäre es eine andere Karte intern verwendet, die Wert speichert, Tastenkombination. Also kann ich anrufen finden? Ist find() in std :: map sequentielle Suche durchführen?

Dank

Antwort

19

Sie können boost::multi_index verwenden, um eine bidirectional map zu erstellen - Sie können beide Werte des Paares als Schlüssel für eine schnelle Suche verwenden.

+0

Sie schlagen mich dazu :) Gute Antwort. –

2

Nein, haben Sie über die std :: map Schleife und überprüfen Sie alle Werte manuell. Je nachdem, was Sie tun möchten, können Sie die std :: map in eine einfache Klasse einbetten, die alle Werte, die in die Map eingefügt werden, auch in einem Verzeichnis zwischenspeichert, das leicht suchbar ist und keine Duplikate zulässt, wie beispielsweise eine Std ::einstellen. Nicht von der std :: map erben (es keinen virtuellen Destruktor haben!), Aber es wickeln, so dass Sie etwas tun können:

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 

Eine Alternative dein eigenes roll wäre Verwenden Sie die bidirektionale Boost-Karte, die Sie in den Posts unten oder bei Google finden.

Es hängt wirklich davon ab, was Sie tun möchten, wie oft Sie es tun möchten und wie schwer es ist, eine eigene kleine Wrapper-Klasse zu erstellen, anstatt Boost zu installieren und zu verwenden. Ich liebe Boost, also ist das ein guter Weg zu gehen - aber es gibt etwas Nettes und Komplettes beim Erstellen eines eigenen Wrapperkurses. Sie haben den Vorteil, die Komplexität von Operationen direkt zu verstehen, und Sie benötigen möglicherweise nicht die vollständige umgekehrte Zuordnung von Werten => Schlüsseln, die von der bidirektionalen Boost-Karte bereitgestellt wird.

+0

Er möchte einen Iterator für das Element, daher sollten Sie eine zweite Map <> anstelle einer Menge <> verwenden. –

14

Wie wäre es mit einer anderen Karte intern, die Wert speichert, Tastenkombination. Also kann ich anrufen finden?

Ja: zwei Karten verwalten, mit einer Karte mit einem Schlüsseltyp und die andere mit dem anderen.

Ist find() in std :: map sequentielle Suche?

Nein, es ist eine binäre Suche eines sortierten Baumes: seine Geschwindigkeit ist O (log (n)).

+0

Das macht Sinn. Wird also die Pflege von zwei Karten eine gute Leistung bringen, als das sequenzielle Suchen und Finden von Werten, oder? –

+3

Es dauert doppelt so lange, um etwas einzufügen oder zu löschen (mit zwei Maps anstelle eines); aber für eine große Anzahl von Elementen ist das Finden viel schneller, weil O (log (n)) viel kleiner ist als das O (n), das für eine sequentielle Suche benötigt wird. – ChrisW

+0

Großer Chris. Vielen Dank. –

15

Wenn Sie Zugriff auf die ausgezeichnete boost Bibliothek haben, dann sollten Sie boost::multi_index verwenden, um bidirectional map zu erstellen, wie Mark sagt. Im Gegensatz zu einer std :: map können Sie damit entweder den Schlüssel oder den Wert nachschlagen.

Wenn Sie nur die STL den folgenden Code zur Hand den Trick (Templat mit jeder Art von Karte zu arbeiten, wo die mapped_type Operator == unterstützt):

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

möglich, dass ich dies nicht tun verstehe ganz, was du erreichen willst. Aber um einfach zu testen, ob eine Karte einen Wert enthält oder nicht, glaube ich, dass Sie die std::map eingebaute find verwenden können.

bool ContainsValue(Type_ value) 
{ 
    return (internalMap.find(value) != internalMap.end()); 
} 
+6

'std :: map :: find' sucht nach Schlüssel, er versucht nach Wert zu suchen. – Dennis

+0

Sie haben absolut recht. Ich denke, wenn Sie die Karte nicht von Hand iterieren und durchsuchen, sollten Sie eine bidirektionale Karte wie den bereits vorgeschlagenen Boost.MultiIndex verwenden. – Ternary

4

versuchen, diese Funktion:

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

Ich denke, es nützlich ist

+2

Korrigieren Sie mich, wenn ich falsch liege, aber ist das nicht nur der Code in der Frage? –

+2

@ JonathanMee Sie liegen nicht falsch. –

0

Was Sie genau fordern ist, was std::find tut (nicht die Member-Funktion)

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

kein sehr gute Option, aber in einigen Fällen nützlich, in denen der Benutzer einen Standardwert wie 0 oder NULL bei init zuweist ialisierung.

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