7

我有两个向量:

struct MyData{
     double value; 
};
std::vector<int> remove_flags = {0, 1, 0, 0, 0, 0, 1, 0};
std::vector<MyData> data =      {{},{},{},{},{},{},{},{}}; 

remove_flags向量包含一个与 大小完全相同的标志数组data,每个标志为 0 或 1,其中 1 表示应删除数据。

我想用来remove_flagsdata原地删除元素,即执行擦除删除习语,但基于remove_flags. 最终结果应该是data删除了元素,并希望remove_flags删除了相同的元素。

手动执行此操作很烦人,我想为此使用 Range-v3。我目前正在使用 C++17。

查看文档后,我认为我没有找到解决方案,我能想到的最接近的是:

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());

但是操作无法对视图 zip 进行操作,因此无法编译。如果我切换ranges::actions::remove_ifranges::views::remove_if返回一个奇怪的视图对象,大概是一个实际上没有std::remove对两个向量执行等效操作的对象。

可以使用contaner_to,但这将涉及副本,我不想为了方便而支付那种不必要的罚款。我已经看到了我想要在 boost 中完成的事情,其中​​可以使用实际的 zip 对迭代器来返回两个单独的删除结果。

Range-v3 中是否可以使用这种模式?

4

1 回答 1

3

对现有范围的急切操作是算法的领域。这里唯一有点棘手的地方是将迭代器恢复到向量中,因为zip它没有给您提供直接获取它们的方法。因此,改为使用新端和范围开始之间的距离来恢复它们:

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());

演示

于 2021-06-05T02:22:13.623 回答