使用范围版本从容器中删除元素的最佳方法

时间:2019-04-22 04:53:03

标签: c++ range

我在代码中遇到一个常见问题,即在满足条件后,我只想从反向的std :: vector中删除单个元素。我知道使用range-v3有很多方法,但是我想出的每种方法似乎有点令人费解。

这是目标向量v的示例:

std::vector v = { 1, 2, 3, 2, 4 };

结果必须是向量r:

std::vector r = { 1, 2, 3, 4 };

这将通过删除反向遍历向量v时发现的前两个(通过lambda谓词“ is_two”)来完成。

这是在原始C ++原始循环中看起来像的样子:

auto is_two = [](int a) { return a == 2; };

for (int i = v.size(); --i >= 0;) {

    if (is_two(v[i])) {

        v.erase(v.begin() + i);
        break;
    }
}

这是我不好的范围-v3版本:

namespace rs = ranges;
namespace rv = ranges::view;
namespace ra = ranges::action;

rs::for_each(v | rv::enumerate
               | rv::reverse
               | rv::filter([](auto i_e) { return i_e.second == 2; })
               | rv::take(1),

            [&](auto& i_e) { v.erase(v.begin() + i_e.first); });

理想情况下,我想知道是否有一些可能看起来像这样的解决方案:

ra::remove_if(v | rv::reverse, is_two);

总而言之,我想知道一个容器如何拿走,通过一些范围的管道进行操作::查看操作,然后从原始容器中删除结果范围内的元素。

2 个答案:

答案 0 :(得分:1)

由于似乎没有人想出一种更好的方法, 为了您的利益,我想提到诉诸旧的reverse_iterator的可能性。

vec.erase(std::prev(ranges::find_if(vec.rbegin(), vec.rend(), is_two).base()));

诚然,这不是很宽泛, 但至少可以奏效。

答案 1 :(得分:1)

基于范围的for循环的主要目的是一致性。对每个元素执行相同的操作。

删除元素会破坏这种一致性。因此,最好的解决方案是普通的for循环,您可以在其中使用迭代器和中断。

当您使用锤子时,一切看起来都像钉子。不要将远程循环锤击成正常的循环。