it-swarm.com.de

Prüfwert existiert in einem std :: map-C++

Ich weiß, dass die Methode find den angegebenen Schlüssel in std :: map findet und einen Iterator an das Element zurückgibt. Gibt es sowieso den Wert zu finden und einen Iterator für das Element zu bekommen? Was ich tun muss, ist zu überprüfen, ob der angegebene Wert in std :: map vorhanden ist. Ich habe dies getan, indem ich alle Elemente in der Karte durchgeschleift habe und miteinander verglichen habe. Aber ich wollte wissen, ob es dafür einen besseren Ansatz gibt.

Folgendes habe ich geschrieben

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 mit einer anderen Karte, die den Wert speichert, eine Tastenkombination. Also kann ich find drauf anrufen? Führt find () in std :: map eine sequentielle Suche durch?

Vielen Dank

30
Navaneeth K N

Sie können boost :: multi_index verwenden, um eine bidirektionale Karte zu erstellen - Sie können einen der beiden Werte des Paares als Schlüssel verwenden, um eine schnelle Suche durchzuführen.

20
Mark Ransom

Wenn Sie Zugriff auf die hervorragende boost - Bibliothek haben, sollten Sie boost :: multi_index verwenden, um bidirektionale Karte zu erstellen, wie Mark sagt. Im Gegensatz zu std :: map können Sie entweder nach dem Schlüssel oder nach dem Wert suchen.

Wenn Sie nur die STL zur Hand haben, erledigt der folgende Code den Trick (es wurde vorgeschlagen, mit jeder Art von Map zu arbeiten, bei der der zugeordnete_Typ den 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;
    }
}
16
CodeBuddy

Wie wäre es mit einer anderen Karte, die den Wert speichert, eine Tastenkombination. Also kann ich find drauf anrufen?

Ja: Pflegen Sie zwei Karten, wobei eine Karte einen Schlüsseltyp verwendet und die andere den anderen.

Findet find () in std :: map eine sequentielle Suche?

Nein, es ist eine binäre Suche nach einem sortierten Baum: Die Geschwindigkeit ist O (log (n)).

15
ChrisW

Sehen Sie sich die bidirektionalen Karten von Boost an: http://www.boost.org/doc/libs/1_38_0/libs/bimap/doc/html/index.html

Dadurch können beide Werte wie ein Schlüssel wirken.

Ansonsten ist Iteration der Weg.

6
Evan Teran

probiere 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 finde es nützlich

4
Mitch

Nein, Sie müssen die std :: map durchlaufen und alle Werte manuell überprüfen. Abhängig von dem, was Sie tun möchten, können Sie die std :: map in eine einfache Klasse einschließen, in der alle Werte, die in die Map eingefügt werden, in einem Cache gespeichert werden, der leicht durchsuchbar ist und keine Duplikate wie std zulässt ::einstellen. Vererben Sie sich nicht von std :: map (es hat keinen virtuellen Destruktor!), Sondern wickeln Sie es so ein, dass Sie Folgendes 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 zum Rollen ist die Verwendung der bidirektionalen Karte von Boost, die in den folgenden Beiträgen oder bei Google leicht zu finden ist.

Es hängt wirklich davon ab, was Sie tun möchten, wie oft Sie es tun möchten und wie schwer es ist, Ihre eigene kleine Wrapper-Klasse zu rollen, anstatt Boost zu installieren und zu verwenden. Ich liebe Boost, das ist also ein guter Weg - aber es ist etwas Nettes und Vollständiges daran, eine eigene Wrapper-Klasse zu erstellen. Sie haben den Vorteil, die Komplexität der Vorgänge direkt zu verstehen und benötigen möglicherweise nicht die vollständige umgekehrte Zuordnung von Werten => Schlüssel, die von der bidirektionalen Boost-Map bereitgestellt werden.

2
James Thompson

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

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

Ich füge diese Antwort hinzu, wenn jemand hierher kommt und nach C++ 11 und höher sucht.

    //DECLARE A MAP
    std::map<int, int> testmap;

    //SAMPLE DATA
    testmap.insert(std::make_pair(1, 10));
    testmap.insert(std::make_pair(2, 20));
    testmap.insert(std::make_pair(3, 30));
    testmap.insert(std::make_pair(4, 20));

    //ELEMENTS WITH VALUE TO BE FOUND
    int value = 20;

    //RESULTS
    std::map<int, int> valuesMatching;

    //ONE STEP TO FIND ALL MATCHING MAP ELEMENTS
    std::copy_if(testmap.begin(), testmap.end(), std::inserter(valuesMatching, valuesMatching.end()), [value](const auto& v) {return v.second == value; });
0
Naidu

Dies ist keine sehr gute Option, kann jedoch in einigen Fällen nützlich sein, in denen der Benutzer bei der Initialisierung einen Standardwert wie 0 oder NULL zuweist. 

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