I've got two vectors:
struct MyData{
double value;
};
std::vector<int> remove_flags = {0, 1, 0, 0, 0, 0, 1, 0};
std::vector<MyData> data = {{},{},{},{},{},{},{},{}};
The remove_flags
vector contains an array of flags of the exact same size as data
, each flag is either 0, or 1, where 1 means the data should be removed.
I would like to use remove_flags
to remove elements from data
in place, ie performing the erase remove idiom, but erasing based on values in remove_flags
. The end result should be data
with elements erased, and hopefully remove_flags
with those same elements erased.
Doing this manually is annoying, and I wanted to use Range-v3 for this. I'm currently using C++17.
After looking through the documentation, I don't think I've found a solution, the closest thing I could come up with is:
auto result = ranges::views::zip(remove_flags, data) | ranges::actions::remove_if([](std::pair<const int&, const MyData&> pair){
return pair.first != 0;
});
remove_flags.erase(result.first, remove_flags.end());
data.erase(result.second, data.end());
But actions cannot operate on the view zip, so this does not compile. If I switch ranges::actions::remove_if
to ranges::views::remove_if
a strange views object is returned, presumably one that has not actually performed the std::remove
equivalent operation on the two vectors.
I could use contaner_to
but that would involve a copy, and I don't want to pay that kind of unnecessary penalty for convenience. I've seen what I want accomplished in boost where actual zip pair iterators can be used to return two separate removal results.
Is this kind of pattern possible in Range-v3?
Range v3 is a generic library that augments the existing standard library with facilities for working with ranges. A range can be loosely thought of a pair of iterators, although they need not be implemented that way.
Disclaimers. The library used in the code examples is not really the C++20 ranges, it's the ranges-v3 open-source library from Eric Niebler, which is the basis of the proposal to add ranges to the C++. It's a header-only library compatible with C++11/14/17.
Eager operation on existing ranges is the domain of algorithms. The only slightly
tricky bit here is recovering iterators into the vectors since zip
doesn't give you a direct way to get those. So instead recover them using the distance between the new end and the start of the range:
auto z = ranges::views::zip(remove_flags, data);
auto e = ranges::remove_if(z, [](auto&& r){ return r.first; });
data.erase(data.begin() + (e - z.begin()), data.end());
remove_flags.erase(remove_flags.begin() + (e - z.begin()), remove_flags.end());
Demo.
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