2

I can write:

my_range | ranges::views::remove(3)

using the ranges-v3 library, to remove the element(s) equal to 3 from the range my_range. This can also be done in C++20 with

my_range | std::views::filter([](auto const& val){ return val != 3; })

But - how can I remove the element at position 3 in my_range, keeping the elements at positions 0, 1, 2, 4, 5 etc.?

Barry
  • 286,269
  • 29
  • 621
  • 977
AnArrayOfFunctions
  • 3,452
  • 2
  • 29
  • 66
  • I made a rather dramatic edit to your question, to simplify it. Feel free to undo the change if you don't like it... – einpoklum Aug 29 '21 at 20:56
  • @einpoklum The [remove] tag you added is currently being burninated actually https://meta.stackoverflow.com/questions/408573 – cigien Aug 29 '21 at 21:50
  • @einpoklum `std::ranges::remove` is an algorithm, not a range adaptor - as you can tell from the fact that it's not in `views::` – Barry Aug 30 '21 at 01:18
  • @Barry: Right... but it still exists. Perhaps it should be mentioned in the question as well? – einpoklum Aug 30 '21 at 05:49

2 Answers2

2

Here's one way to do it:

#include <iostream>
#include <ranges>
#include <range/v3/view/take.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/concat.hpp>

int main() {
    const auto my_range = { 10, 20, 30, 40, 50, 60, 70 };
 
    auto index_to_drop = 3; // so drop the 40
    auto earlier = my_range | ranges::views::take(index_to_drop - 1);
    auto later = my_range | ranges::views::drop(index_to_drop);
    auto both = ranges::views::concat(earlier, later);
    for (auto const & num : both) { std::cout << num << ' '; }
}

This will produce:

10 20 30 50 60 70

... without the 40.

See it working on Godbolt. Compilation time is extremely poor though. Also, concat() is not part of C++20. Maybe in C++23?

cigien
  • 57,834
  • 11
  • 73
  • 112
einpoklum
  • 118,144
  • 57
  • 340
  • 684
2

The most straightforward way I can think of in range-v3 would be:

auto remove_at_index(size_t idx) {
    namespace rv = ranges::views;
    return rv::enumerate
         | rv::filter([=](auto&& pair){ return pair.first != idx; })
         | rv::values;
}

To be used like:

my_range | remove_at_index(3);

enumerate (and its more general cousin zip) is not in C++20, but will hopefully be in C++23.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • Thought about this, was reminded of [this question](https://stackoverflow.com/a/11329249/1593077), but didn't remember it was easy with ranges-v3. Thanks and +1. – einpoklum Aug 30 '21 at 08:38
  • Please could you add an example about how this could be done with actions (if possible)? Thanks – SamG101 Aug 24 '22 at 11:46