I have an unordered_map looking 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 same value lets say "a". Any suggestions beside the obvious way:
std::vector<int> arrKeys;
std::string value = "a";
for (const auto& element : theMap)
if (element.second == value)
arrKeys.push_back(element.first);
I think the "obvious" way is excellent: it is simple, short and easy to read.
Another option is to use stl algorithms. What you need is 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 is no such in stl. What I can suggest is:
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);
}
More out of interest than anything else, I wrote a basic wrapper which could be used for copy_if
. It is like std::back_inserter
, but instead of just inserting the object it is given, it inserts std::get<N>(obj)
. This makes it usable for std::array
, std::tuple
and std::pair
.
To insert the 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 a 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 suggestions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With