如何使用erase函数按索引从std::vector<>中删除多个元素?

9

我有一个向量a存储值[0 1 2 3 5],还有另一个向量removelist 存储要删除的索引[0 1 2],以便最终得到[3 5]。当我实现以下代码时,它会意外地删除项目,因为在过程中向量a的顺序将发生改变。有没有办法实现我的目标?

 for (int i = 0; i<removelist.size() ; i++)     
    a.erase(a.begin() + removelist[i]);

1
removelist 是否有序? - tkausl
@tkausl 更重要的是,一切似乎都是有序的。我想问一下这是否属实。每个数组实际上都是有序的吗? - skypjack
移除列表并不是有序的,但如果需要的话可以进行排序。 - Tleung
@skypjack,如果“a”向量是按顺序排列的,那也没关系,因为他是通过索引而不是值来删除它的。但他的示例有错误(在大小为5的向量中没有索引5)。 - tkausl
也许你误解了我的问题。removelist 是一个参考列表,用于删除 a[0]、a[1] 和 a[2]。 - Tleung
4个回答

7
使用removelist的反向迭代器,以相反的顺序删除值。当然,这要求removelist已经按照顺序排列好了。
也许可以这样做:
std::sort(removelist.begin(), removelist.end());  // Make sure the container is sorted
for (auto &i = removelist.rbegin(); i != removelist.rend(); ++ i)
{
    a.erase(a.begin() + *i);
}

2

不一定更高效,但您可以使用remove_if而无需排序来执行此操作:

auto& rm = removelist; // for brevity

a.erase(remove_if(begin(a), end(a), [&](int i) {
  auto idx = distance(begin(v), find(begin(v), end(v), i));
  return find(begin(rm), end(rm), idx) != end(rm);
}, end(a));

注意:当向量“v”中的元素不唯一时,使用“find(begin(v), end(v), i)”将导致意外结果。 - keineahnung2345

1
解决方法是将要保留的元素复制到一个新向量中:
// pseudocode:
vector tmp;
tmp.reserve(a.size() - removelist.size());
for (i=0; i<a.size(); ++i) {
    if (i not in removelist) {
        tmp.push_back(a[i]);
    }
}
a.swap(tmp);

注意:

  • 您必须确保索引是唯一的,否则预分配将失败。
  • 这样可以避免使用预分配的临时向量进行各种重新分配。对于a的重新分配也避免了您的方法中的索引移位。
  • 如果removelst中的元素已排序,则可以更有效地实现此操作。
  • 我想知道那个列表来自哪里。您能否在创建临时列表之前即时删除元素?

临时列表是通过一些比较生成的。 - Tleung

0

改编自@Yam Marcovic的答案,不使用find而是使用确切的地址来查找索引:

a.erase(std::remove_if(a.begin(), a.end(), [&](const int& i) {
  auto idx = ((void*)&i - (void*)&*a.begin());
  return std::find(removelist.begin(), removelist.end(), idx) != removelist.end();
}), a.end());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接