Search for all keys matching a single value in std :: unordered_map

I have an unordered_map that looks like this:

std::unordered_map<int, std::string> theMap2 = {{1,"a"}, {2,"b"}, {3,"c"}, {4,"a"}}; 

I want to find all the keys that have the same value, lets say "a". Any suggestions in an obvious way:

 std::vector<int> arrKeys; std::string value = "a"; for (const auto& element : theMap) if (element.second == value) arrKeys.push_back(element.first); 
+6
source share
2 answers

I think the β€œobvious” way is excellent: it's simple, short, and easy to read.

Another option is to use stl algorithms. You need the transform_if algorithm, so you can say:

 std::transform_if(std::begin(theMap), std::end(theMap), std::back_inserter(arrKeys), check_value, get_value); 

but there are none in stl. I can suggest the following:

 std::vector<int> arrKeys; std::string value = "a"; auto check_value = [&](std::pair<const int, std::string> const& p)->bool { return (p.second == value); }; auto end = std::end(theMap); auto it = find_if(std::begin(theMap), end, check_value); while (it != end) { arrKeys.push_back(it->first); it = find_if(std::next(it), end, check_value); } 
+9
source

More out of interest than anything else, I wrote a basic wrapper that can be used for copy_if . This is similar to std::back_inserter , but instead of just pasting an object, it inserts std::get<N>(obj) . This makes it suitable for std::array , std::tuple and std::pair .

To insert pair.first , as we want in this example, we use back_n_inserter<0> .

 template< std::size_t N, class Container > class back_n_insert_iterator : public std::iterator< std::output_iterator_tag, void, void, void, void > { public: back_n_insert_iterator (Container& c) : c{c} {}; //could protect this by checking that the get call is_convertible to the value_type template <typename T> decltype(auto) operator= (T&& collec) { c.push_back(std::get<N>(std::forward<T>(collec))); return *this; } decltype(auto) operator* () { return *this; } decltype(auto) operator++ () { return *this; } decltype(auto) operator++ (int) { return *this; } private: Container& c; }; template< std::size_t N, class Container > back_n_insert_iterator<N,Container> back_n_inserter( Container& c ) { return {c}; } 

Now we can use our adapter in the copy_if call:

 std::copy_if(theMap.begin(), theMap.end(), back_n_inserter<0>(arrKeys), [&value](const auto& el){return el.second == value;}); 

Thanks to @dyp for all the suggestions.

+2
source

Source: https://habr.com/ru/post/989278/


All Articles