从c ++向量中删除已知的项子集

时间:2016-10-27 00:49:48

标签: c++ vector boost stl

假设:

  • 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算法。)

3 个答案:

答案 0 :(得分:2)

由于已知idsToRemove中的ID位于items并且顺序相同,因此可以使用几个迭代器到items来跟踪当前的比较元素,当前目的地,并通过idsToRemoveitems,比较两个元素,移动您想要保留的元素。在该过程结束时,将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是向量中元素的数量。