cauchi
cauchi

Reputation: 1543

how to use map::find on map of maps

I'm having an issue making some unit tests in a large code base. Basically I need to find a value in map of maps. I wrote a code snippet to explain what my problem is. The following represents how the data is build:

map<string, map<string, string>> testmap;
map<string, string> item;
item.insert(pair<string,string>("hello","world"));
testmap.insert(pair<string, map<string,string> > ("key",item));

then, at some later point, I need to check that the values have been added before obtaining a key. From the cppreference, the return of the [] operator is

Reference to the mapped value of the new element if no element with key key existed. Otherwise a reference to the mapped value of the existing element whose key is equivalent to key.

If I understand correctly, which from the comments is clear that I am not, this means that a new element is inserted if there was no element with that key. I want to avoid that, and return an error message.

The following is wrong and I'm trying to understand why:

if (testmap.find(map<string,string>("hello","world")) != testmap.end()) 
{
    ...
    return testmap["hello"]["world"];
}

Upvotes: 1

Views: 2056

Answers (2)

sklott
sklott

Reputation: 2849

It seems to me that what you want is testmap.find("key"), i.e. search for key, but for some reason you think that you should search for value...

Upvotes: 1

Daniel Langr
Daniel Langr

Reputation: 23497

To find a value in a map, you cannot use find member function, which finds a key. However, you can find a value, e.g., by using std::find_if with a custom comparator:

using value_t = std::map<std::string, std::string>;
using key_t = std::string;
using map_t = std::map<key_t, value_t>;

map_t m { { "key" , { { "hello", "world" } } } };

value_t v { { "hello", "world" } };  // value to be found
auto iter = std::find_if(m.begin(), m.end(),
               [&v](const auto& e){ return e.second == v; });
std::cout << (iter != m.end()) << std::endl;

Live demo: https://wandbox.org/permlink/1b0bjbnnPY8E0uiU


Note that this will work since C++14. In C++11, you need to write:

auto iter = std::find_if(m.begin(), m.end(),
               [&v](const map_t::value_type& e){ return e.second == v; });

UPDATE

It's still kind-of unclear to me what you are trying to achieve. If you need a reference to the inner-most value only if it's both-level keys exist, then you can do (C++17 syntax):

if (auto i1 = m.find("key"); i1 != m.end())
   if (auto i2 = i1->second.find("hello"); i2 != i1->second.end())
      std::cout << i2->second << std::endl;  // same as m["key"]["hello"] here but faster

Upvotes: 4

Related Questions