简体   繁体   中英

How to check if a `std::vector<bool>` is true at multiple indexes simultaneously?

I have a std::vector<bool> of size N and a std::vector<std::size_t> of variable size containing indexes in [0, N) . What is an idiomatic way to check if the first vector is true at all indexes given by the second vector?

My possibly naive solution is:

auto all_true(
    std::vector<bool> const& bools, std::vector<std::size_t> const& indexes)
    -> bool {
  auto res = true;
  for (auto index : indexes) {
    res = res and bools[index];
  }
  return res;
}

An idiomatic (though not necessarily efficient ) way to do this would be to use the std::all_of STL function , using a predicate that simply returns the value of the Boolean vector at the index specified by each value in the size_t vector.

Here's an outline/demo:

#include <iostream>
#include <vector>
#include <algorithm>
#include <random>

bool all_true(const std::vector<bool>& data, const std::vector<size_t>& test)
{
    return std::all_of(test.begin(), test.end(), [&data](size_t n) { return data[n]; });
}

int main()
{
    std::vector<bool> bools{ true, true, true, true, false, false, true, false, true, false };
    std::vector<size_t> test1{  0,    1,    2,    3,                  6,           8        }; // all true
    std::vector<size_t> test2{  0,    1,    2,           4,                  7,           9 }; // some false

    std::cout << "Test1: " << all_true(bools, test1) << "\n";
    std::cout << "Test2: " << all_true(bools, test2) << "\n\n";

    // Just to show that the order doesn't matter ...
    std::cout << "After shuffling ...\n";
    std::random_device rdev;
    std::mt19937 rgen(rdev());
    std::shuffle(test1.begin(), test1.end(), rgen);
    std::shuffle(test2.begin(), test2.end(), rgen);
    std::cout << "Test1: " << all_true(bools, test1) << "\n";
    std::cout << "Test2: " << all_true(bools, test2) << "\n";

    return 0;
}

Don't think your code is not idiomatic.
The range based for() is there to handle this type of situation. Especially if you are writing a named function to encapsulate it.

auto allTrue(std::vector<bool> const& data, std::vector<std::size_t> const& indexs) -> bool
{
    for (auto index: indexs) {
        if (!data[index]) {
            return false;
        }
    }
    return true;
}

Pre range based iterator I would say use a standard function that uses iterators.

auto allTrue(std::vector<bool> const& data, std::vector<std::size_t> const& indexs) -> bool
{
    return std::all_of(std::begin(indexs), std::end(indexs),
                [&data](std::size_t i){return data[i];}
           );
}

Maybe: If you are not going to wrap it in a function then using this std::all_of() function directly in place in the code it makes it more intuitive to read, then use it. But if you are writing the function anyway use the range based for.

Or if you have C++20

auto allTrue(std::vector<bool> const& data, std::vector<std::size_t> const& indexs) -> bool
{
    return std::ranges::all_of(indexs, [&data](std::size_t i){return data[i];});
}

Yet another option would be std::accumulate . If the result type and the input std::vector element type were the same, you could instead use a (more efficient) std::reduce . However, in this case you need to (sort of) accumulate size_t s (indices pointing into a std::vector of bool s) into a bool result:

#include <iostream>
#include <numeric>
#include <vector>

int main() {
  const std::vector<bool> bools{true, true, false, true, true};
  const std::vector<size_t> i1{1, 4, 3, 0};  // true && true && true && true
  const std::vector<size_t> i2{0, 2, 4, 3};  // true && false && true && true

  const auto and_by_idx{
      [&bools](bool acc, size_t idx) { return acc && bools[idx]; }};

  std::cout << std::boolalpha
            << std::accumulate(i1.begin(), i1.end(), true, and_by_idx) << '\n'
            << std::accumulate(i2.begin(), i2.end(), true, and_by_idx) << '\n';
}

I wouldn't call any of the C++ solutions idiomatic though. Some other languages have shorter and more elegant ways to express this, like Python and its all() .

bools = (True, True, False, True, True)
i1 = (1, 4, 3, 0)  # True && True && True && True
i2 = (0, 2, 4, 3)  # True && False && True && True

print(all(bools[i] for i in i1))
print(all(bools[i] for i in i2))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM