0

I have a problem accessing a Map by value. I do not want to access the value using find("string_value"), but as find(s) while string s="string_value". See below:

map<string, string> my_map; string s; map<string, string>::iterator it_; for(it_ = my_map.begin(); it_!= my_map.end(); it_++) { s = it_->second; if (my_map.find(s) != my_map.end()) cout << my_map.find(s)->second << endl; } 

My initial guess is that find() accepts const value while it_->second is not. So even if my map had the value, the if condition fails. There were no compile time errors though. Any help?

5
  • I don't understand why you iterate trough the map to find the values that you are already pointing too... Commented May 13, 2013 at 22:32
  • std::map models a mapping from the key to the value - it's a one way relationship. You can't use the value to get the corresponding key. Commented May 13, 2013 at 22:32
  • 2
    Your initial guess is wrong, since comparison does not care about constness. Commented May 13, 2013 at 22:33
  • 1
    What is it that happens that you do not expect? As far as I can tell, this code works fine. Commented May 13, 2013 at 22:38
  • Thanks for the suggestions/comments. I realized that find(s) sort of feature doesn`t exist using map. The best bet would be to use boost bimap. However, am not sure if we can have a custom find method that accomplishes what I needed. Commented May 14, 2013 at 1:27

3 Answers 3

3

You should look into Boost, specifically the bimap class.

http://www.boost.org/doc/libs/1_42_0/libs/bimap/doc/html/index.html

This will let you make a map where both sides are searchable.

Regular STL maps are only searchable on the key, not the value.

Sign up to request clarification or add additional context in comments.

Comments

2

When you say my_map.find(s) the map doesn't know that you're looking for a value, and it can't possibly know that, instead it looks for the key s

So if your map doesn't also contain that value as a key then the lookup will never succeed, and even if it does contain that key it might not be the element you're looking for.

For example if your map contains { {"one", "two"}, {"two", "three"} } then on the first iteration you'll search for "two" which returns {"two", "three"}, and on the second iteration you'll search for "three" which fails.

There's no compile-time error because you're asking the map to find a string, and its key type is string, so it searches for a key equal to that string.

Comments

0

I also had this problem a few weeks ago. I solved it as following:

#include <iostream> #include <map> #include <string> using namespace std; int main() { map<string, string> m; m.insert(pair<string,string>("black", "yellow")); m.insert(pair<string,string>("green", "blue")); auto found = m.end(); string search = "blue"; for(map<string, string>::iterator itr = m.begin(); itr != m.end(); itr++) { if(itr->second.find(search) != string::npos) { found = itr; } } if(found != m.end()) { cout << found->second; } } 

But this code was written with the C++11 standard so be careful if you are working with an older compiler.

8 Comments

Of course, it can be done. But is there a point to searching a map for a value? They are meant to associate a particular key with a particular value, it's the association that you should be interested in, not the value.
The question asks if the key can be an input variable. The above code is not satisfactory because find("blue") assumes you already know that the key called "blue" exists.
why use m.insert() instead of the more efficient m["black"] = "yellow" or m.emplace("black", "yellow")? Why use auto for m.end() but not for m.begin()? Why not use the new range-based for loop? Why use find("blue") not iter->second == "blue"?
@JonathanWakely The container map is implemented as a binary tree so it takes always the same time to add a new node. It doesn't matter if you use the method insert() or you use the operator[]. Both have the same complexity of logarithmic in size n. The problem of this new range-based for loop is that auto deduces the following type: for(pair<string, string> itr : m) { cout << itr.first; } But this doesn't bring you anything because you have just an iterator to each element but you have no access to the address where this pair is saved in the tree. *found = itr isn't possible
@akella No the code doesn't assume that the key "blue" already exists. You search for this key and if this key doesn't exist your found-iterator still points to the end of the map. So you can check after the search whether the found-iterator still shows to the end of the map or not.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.