【发布时间】:2016-10-27 00:49:48
【问题描述】:
给定:
struct Item { int id; ... };std::vector<Item> items;std::vector<int> idsToRemove;
编写执行删除(同时保持顺序)的代码的最有效/最简洁的方法是什么?
使用remove_if,这可能是:
items.erase(std::remove_if(items.begin(), items.end(),
[&](const Item& i) {
return std::find(idsToRemove.begin(), idsToRemove.end(), i.id)
!= idsToRemove.end();
}), items.end());
另一种可能是:
for (auto id : idsToRemove)
{
items.erase(std::remove(items.begin(), items.end(), id), items.end());
// or items.erase(std::find(items.begin(), items.end(), id));
// provided that we know id always exists in items
}
这两种感觉都不是特别好(而且它们看起来都O(N*M)),尽管第二个看起来比第一个更整洁。有没有更好的办法?
(如果有帮助,虽然两个向量都没有排序,但已知idsToRemove 是 id 的子集,其顺序与它们在items 中出现的顺序相同,并且两个数组都很小。我可以使用 Boost如果那里有合适的算法。)
【问题讨论】:
-
您可以将擦除删除限制在由匹配 next ID 的第一个项目分隔的子范围内。如果你从后面这样做,你可以最大限度地减少移动量。
-
不,如前所述,阵列通常很小。我主要是在寻找代码的简洁性,但我也不希望它不必要地低效。
-
如果它是大的任意列表,我会制作 idsToRemove 的哈希或布隆过滤器,因此您可以在迭代项目时在 O(1) 时间内检查它们。但鉴于相同的订单子集保证,这完全没有必要。既然你说向量很小,O(NM) 并不是那么糟糕,但我投票支持 1201ProgramAlarm 的答案。它是 O(N) 空间和时间,但您必须自己编写。我认为上述快速解决方案的真正问题是从向量中删除一堆单个项目本身就是一个缓慢的过程。