假设:
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算法。)
答案 0 :(得分:2)
由于已知idsToRemove
中的ID位于items
并且顺序相同,因此可以使用几个迭代器到items
来跟踪当前的比较元素,当前目的地,并通过idsToRemove
和items
,比较两个元素,移动您想要保留的元素。在该过程结束时,将items
调整为新的较小尺寸。
答案 1 :(得分:0)
我不认为这是对所述问题的真实答案(因为它移动了球门柱),但这是我在调查时发现的,它可能对将来的搜索有用。
如果您没有从外部传递idsToRemove
,但需要迭代items
来决定删除哪个,那么有一个相当不错的方法来执行此操作O(N):
#include <boost/range/algorithm_ext/erase.hpp>
boost::range::remove_erase_if(items, [&](const Item& item)
{
// do whatever else you want to item
// return true to erase the item, or
return false; // to keep it
});
在内部,它基于std::remove_if
,但它更加整洁,类似于基于范围的。
答案 2 :(得分:0)
我认为您的元素具有唯一ID,因此不要将要删除的元素存储在std::vector
中,而只需将它们存储在std::unordered_set
中。
这样,std::remove_if
方式非常干净:
struct Item {
int id;
};
// ...
std::vector<Item> items;
std::unordered_set<int> idsToRemove;
items.erase(
std::remove_if(std::begin(items), std::end(items), [&](Item const& it) {
return (idsToRemove.find(it.id) != std::end(idsToRemove));
}),
std::end(items));
复杂性(摊销)将是O(N)
,其中N
是向量中元素的数量。