使用remove_if通过索引从C++向量中移除

Removing by index from a C++ vector using remove_if

本文关键字:向量 C++ 索引 remove if 使用      更新时间:2023-10-16

我们可以在C++中使用remove_if,根据对元素进行运算的谓词,在线性时间内从向量中删除元素。

bool condition(double d) {...}
vector<double> data = ...
std::remove_if (data.begin(), data.end(), condition);

如果我的条件不是取决于数值,而是取决于指数,该怎么办?换句话说,如果我想删除所有奇数索引元素,或者一些任意索引集,等等?

bool condition(int index) {//returns whether this index should be removed}
vector<double> data = ...
std::remove_if (data.begin(), data.end(), ???);

您可以使用指针算术来查找std::remove_if传递给谓词的特定元素的索引:

std::remove_if(data.begin(), data.end(),
               [&data](const double& d) { return (&d - &*data.begin()) % 2); });

请注意,remove_if传递对迭代器取消引用的结果,并且根据标准中的表106-迭代器要求,这保证是reference

我实际上只是为此做了一个帐户。使用令人敬畏的答案。更干净。

int count = 0;
auto final = std::remove_if (data.begin(), data.end(), [&count](const double d) {
    return (count++) % 2;
});

标准中确实规定了谓词的应用时间是倒数第一次。remove_if与ForwardIterators配合使用。

这意味着谓词只按它们最初出现在序列中的顺序应用一次。

当然,除非库通过保留ForwardIterator的内部副本来对您进行恶意攻击。

利用lambas可以捕获变量这一事实。举个简单的例子:

vector<double> data = {5, 3, 6, 7, 8};
int count = 0;
auto final = std::remove_if (data.begin(), data.end(), [&](const double d) {
    bool b = false;
    if(count % 2) b = true;
    ++count;
    return b;
});
for(auto beg = data.begin(); beg != final; ++beg)
    cout << *beg << endl;

代码将打印:5 6 8

类似于std::remove_if的算法,但将索引传递给其谓词

template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_indexes_if(ForwardIt first, ForwardIt last, UnaryPredicate p)
{
    ForwardIt dest = first;
    for(ForwardIt i = first; i != last; ++i)
        if (!p(std::distance(first, i)))
            *dest++ = std::move(*i);
    return dest;
}