C++ 从c+中删除已知的项目子集+;矢量
鉴于:C++ 从c+中删除已知的项目子集+;矢量,c++,vector,boost,stl,C++,Vector,Boost,Stl,鉴于: struct项{int id;…} std::向量项 std::vector idsToRemove 编写执行删除(同时保留顺序)的代码的最有效/最干净的方法是什么 使用删除\u如果,这可能是: items.erase(std::remove_if(items.begin(), items.end(), [&](const Item& i) { return std::find(idsToRemove.begin(), idsToRemove.
struct项{int id;…}代码>
std::向量项代码>
std::vector idsToRemove代码>
删除\u如果
,这可能是:
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的一个子集,它们在项中出现的顺序相同,而且两个数组都很小。如果有合适的方法,我可以使用Boost算法。)由于已知idsToRemove
中的ID位于项中,且顺序相同,因此您可以在项中使用两个迭代器来跟踪当前比较元素、当前目标以及遍历idsToRemove
和项,比较这两个元素,移动那些你想保留的。在这个过程结束时,调整大小>代码>项目<代码>是新的更小的大小。 我不认为这是对问题的真实回答(因为它移动了GoalPoST),但这是我在调查它时发现的东西,它可能对将来的搜索有用。
如果您没有从外部传入idsToRemove
,但仍然需要遍历项来决定要删除哪些项,那么有一种相当好的方法可以在O(N)中执行此操作:
#包括
boost::range::remove_erase_if(items,[&](const Item&Item)
{
//做任何你想做的事情
//返回true以删除该项,或
return false;//保存它
});
在内部,它是基于std::remove_if
,但它更整洁,类似于基于范围的。我想您的元素有唯一的ID,所以与其将要删除的元素存储在std::vector
中,不如将它们存储在std::unordered_集合中
这样,std::remove_如果方式非常干净:
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));
struct项{
int-id;
};
// ...
向量项;
std::无序设置idsToRemove;
项目。删除(
std::删除_if(std::开始(项目),std::结束(项目),[&](项目常量和it){
return(idsToRemove.find(it.id)!=std::end(idsToRemove));
}),
标准:结束(项目));
复杂度(摊销)将是O(N)
,其中N
是向量中的元素数。您可以将擦除移除限制在由与下一个ID匹配的第一个项目分隔的子范围内。如果您从后面执行此操作,则可以将移动量降至最低。不,如上所述,数组通常很小。我主要寻求代码的简洁性,但我也不希望它毫无必要地低效。如果它是大型任意列表,我会制作一个IDStoreReve的哈希或bloom过滤器,这样您可以在迭代项目时在O(1)时间内检查它们。但考虑到相同的顺序子集保证,这是完全不必要的。既然你说向量很小,O(NM)也没那么糟糕,但我投票赞成1201程序的答案。这是空间和时间,但你得自己写。我认为您上面的快速解决方案的真正问题是,从向量中删除一组单个项本身就是一个缓慢的过程。这听起来像是编写一个自定义的remove\u if
。我主要是想看看是否有一个现有的STL或Boost算法或组合已经从向量中删除了向量(这似乎应该是常见的,不是吗?)(在到达idsToRemove
的末尾后,您将比较项中的尾部元素,并且需要在对迭代器进行去帧之前检查该结尾)。这里的关键洞察是,您可以对项目进行一次迭代,并且可以通过一次迭代将其与IDStoreRemove进行比较。您从不备份,因为您知道它是按相同顺序排列的子集。我被多个迭代器搞糊涂了,但您所说的是使用原始向量对内容进行无序排列,这样您就永远不会受到攻击vector delete的性能冲击。(我花了一分钟才明白你说的话。)@米拉尔:实际上STL并没有提供这样的功能,因为它并不常见。有一个向量是另一个向量的子集,并且额外保证元素的顺序与第一个相同,这是一种边缘情况。在任何情况下,将两个迭代器(因此效率更高)保留在几行代码中都是非常简单的。
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));