Using std::any_of, std::all_of, std::none_of etc with std::map
Asked Answered
C

5

9
std::unordered_map<std::string, bool> str_bool_map = {
    {"a", true},
    {"b", false},
    {"c", true}
};

can we use std::any_of on this map to see any of its values is false? Or any of its key is let's say "d"?

Similarly can we use std::all_of or std::none_of on this map?

Calise answered 7/1, 2020 at 8:11 Comment(0)
O
13

The simplest solution is to use a lambda:

std::unordered_map<std::string, bool> str_bool_map = 
    {{"a", true}, {"b", false}, {"c", true}};

bool f = std::any_of(str_bool_map.begin(), str_bool_map.end(),
    [](const auto& p) { return !p.second; });

Here the lambda expression [](...) { ... } is a unary predicate that takes const auto& p and makes the test. const auto& will be deduced to const std::pair<const std::string, bool>& (= std::unordered_map<...>::value_type), that's why you use .second to test the bool part of a pair. Use .first member to test the element's key.

Occasionally answered 7/1, 2020 at 8:13 Comment(1)
thanks, I was not writing the predicate correctly and thought it does not workCalise
S
5

Quick answer: What happens when you try?

Another quick answer: Yes

Reason: Looking at this page we can see that std::all_of and friends expect that:

InputIt must meet the requirements of LegacyInputIterator.

Now, std::map.begin() returns a LegacyBidirectionalIterator

Finally, looking at the table here we can see that LegacyBidirectionalIterator is a kind of LegacyInputIterator, so therefore you can use an std::map with std::all_of and friends.

Stockholm answered 7/1, 2020 at 8:23 Comment(1)
thanks, I was not writing the predicate correctly and thought it does not workCalise
T
1
#include <algorithm>
#include <map>

int main()
{
    std::map<std::string, bool> map;
    map["foo"] = false;
    map["bar"] = true;
    map["baz"] = false;

    const bool any = std::any_of(map.begin(), map.end(), [](const auto& pair)
    {
        return !pair.second;
    });

    const bool all = std::all_of(map.begin(), map.end(), [](const auto& pair)
    {
        return !pair.second;
    });

    const bool none_of = std::none_of(map.begin(), map.end(), [](const auto& pair)
    {
        return !pair.second;
    });
}
Tartaric answered 7/1, 2020 at 8:20 Comment(0)
G
1

In C++20, std::ranges::any_of can be used with the std::views::keys and std::views::values range adaptors which create views of the map's keys and values, respectively.

Also, the false-checking lambda can be replaced with std::logical_not (std::identity would be used to test for true).

// #include <algorithm>
// #include <ranges>
std::ranges::any_of(std::views::values(str_bool_map), std::logical_not());
std::ranges::any_of(std::views::keys(str_bool_map), [](const auto& k) { return k == "d"; });
Gentianella answered 19/8 at 16:7 Comment(0)
J
0

Iterating over a map yields key-value pairs. So you can just pass a lambda to the algorithm to unpack the key value pair.

To check a val, use .second:

std::any_of(m.begin(), m.end(), [](const auto& kvp){ return kvp.second; });

To check keys, use .first:

std::any_of(m.begin(), m.end(), [](const auto& kvp){ return kvp.first == "d"; }) 

Live code here.

Jarrad answered 7/1, 2020 at 8:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.