Ell*_*ith 5 c++ stl erase-remove-idiom stl-algorithm c++20
我经常发现自己想要根据向量的索引而不是值来过滤向量。
auto some_values = std::vector{1, 0, 4, 6, 2};
// Somewhere I figure out which items to remove.
// This may be from user interaction or something
// nothing to do with the original values:
const auto removing = std::vector<bool>{0, 0, 1, 0, 1};
Run Code Online (Sandbox Code Playgroud)
erase_if所以,我很想像这样使用:
std::erase_if(some_values, [it = removing.begin()](auto) mutable {return *it++;});
Run Code Online (Sandbox Code Playgroud)
它似乎适用于 gcc 和 clang。但是, std::erase cppref 页面上似乎没有任何关于谓词调用顺序的内容,所以我认为这是未定义的行为?
与 相同的问题std::remove_if。请注意,压缩范围不适用于大多数压缩选项,因为通常生成的范围无法调整基础数据的大小。
使用 for 循环并创建数组的副本并不是太多的样板文件,但我目前正在将过滤器应用于一些低级代码,在这些代码中我无法复制所有数据。有些数据会很大,需要在这些过滤操作期间做出响应。
最坏的情况我可以添加这样的函数来解决问题:
template <class T, auto N, class Pred>
size_t RemoveIfIndex(std::span<T, N> span, Pred&& pred)
{
size_t write = 0; // Also behaves as a counter
// Initialise to the first deleted index:
for (; (write < span.size()) && !pred(write); ++write);
// Shuffle the elements:
for (size_t read = write + 1; read < span.size(); ++read)
{
if (!pred(read))
{
span[write] = span[read];
++write;
}
}
return write;
}
template <class T, class Alloc, class Pred>
size_t EraseIfIndex(std::vector<T, Alloc>& vec, Pred&& pred)
{
const size_t new_size = RemoveIfIndex(std::span{vec.begin(), vec.end()}, pred);
vec.resize(new_size);
return new_size;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我需要添加类似的函数类别(需要索引信息)时,我犹豫是否要向我们的低级库添加更多代码,并且我怀疑我对范围/适配器/过滤器有一些了解缺少这一点将使这些功能变得不必要。
P K*_*mer -1
== 警告不正确的示例,出于教育目的而保留 == (remove_if 在内存中移动元素,因此索引在迭代期间不会对齐)
为什么是最坏的情况?拥有工作功能是一种很好的工作方式。它并不总是关于最少的代码行数。无论如何,我会创建一个函数来检查边界条件(例如向量大小应该匹配)
#include <algorithm>
#include <iostream>
#include <vector>
#include <stdexcept>
void remove_by_index(std::vector<int>& values, const std::vector<bool>& filter)
{
if (values.size() != filter.size()) throw std::invalid_argument("");
std::size_t index{ 0 };
auto it = std::remove_if(values.begin(), values.end(), [&](const auto) { return filter[index++]; });
values.erase(it, values.end());
}
int main()
{
auto some_values = std::vector{ 1, 0, 4, 6, 2 };
const auto remove = std::vector<bool>{ 0, 0, 1, 0, 1 };
remove_by_index(some_values, remove);
for (const auto value : some_values)
{
std::cout << value << " ";
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
293 次 |
| 最近记录: |