【问题标题】:Removing by index from a C++ vector using remove_if使用 remove_if 按索引从 C++ 向量中删除
【发布时间】:2014-06-01 02:23:58
【问题描述】:

我们可以在 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(), ???);

【问题讨论】:

标签: c++ vector indexing iterator remove-if


【解决方案1】:

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

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

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

【讨论】:

  • 谢谢。你能解释一下为什么你有&amp;*data.begin()而不是data.begin()吗?
  • @donnyton 因为 begin() 返回一个迭代器,但我们想将它与参数的地址(即指针)进行比较,因此 &* 舞蹈......
  • 我不认为标准保证这会起作用,因为它假设在应用谓词之前元素没有移动/交换。该标准仅保证准确应用谓词last - first 次。 AFAICT 实现可以在应用谓词之前移动/交换元素,这很愚蠢,但符合标准。
  • @DDrmmr:还有“为了确定数据竞争的存在,算法不应修改通过迭代器参数引用的对象,除非规范要求进行此类修改。” - 最小化数据竞争的规定还应禁止在应用谓词之前进行不必要的移动/交换(至少与容器的其他成员)。
  • 这只适用于ContiguousIterators,而std::remove_if只需要ForwardIterator
【解决方案2】:

我实际上只是为此创建了一个帐户。使用 awesomeyi 答案。更干净。

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

标准确实说谓词是最后一次应用的——第一次。并且 remove_if 与 ForwardIterators 一起使用。

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

当然,除非库通过保留 ForwardIterator 的内部副本来欺骗您。

【讨论】:

  • 我很确定它允许实现做一些事情,比如迭代保持元素的地址,然后在线程中应用谓词或使用一些并行指令,所以我不认为这是特别的安全。
【解决方案3】:

利用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

【讨论】:

  • 这对remove_if 应用谓词的顺序做出了假设,标准文本不保证这一点。
【解决方案4】:

一种算法类似于 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;
}

【讨论】:

    猜你喜欢
    • 2019-01-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多