Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing elements marked for removal with Ranges-V3

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?

like image 818
Krupip Avatar asked Jun 03 '21 20:06

Krupip


People also ask

What is 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.

Is range v3 header only?

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.


Video Answer


1 Answers

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.

like image 162
T.C. Avatar answered Oct 19 '22 19:10

T.C.