从向量中删除项目的有效方法

时间:2010-10-27 08:35:35

标签: c++

目前,我计划从矢量中移除所有项目,这在集合中找不到。

例如:

#include <vector>
#include <set>
#include <string>
#include <iostream>

using namespace std;

int main() {
    std::set<string> erase_if_not_found;
    erase_if_not_found.insert("a");
    erase_if_not_found.insert("b");
    erase_if_not_found.insert("c");

    std::vector<string> orders;
    orders.push_back("a");
    orders.push_back("A");
    orders.push_back("A");
    orders.push_back("b");
    orders.push_back("c");
    orders.push_back("D");

    // Expect all "A" and "D" to be removed.
    for (std::vector<std::string>::iterator itr = orders.begin(); itr != orders.end();) {
        if (erase_if_not_found.find(*itr) == erase_if_not_found.end()) {
            orders.erase(itr);
            // Begin from start point again? Do we have a better way?
            itr = orders.begin();
        } else {
            ++itr;
        }
    }

    for (std::vector<std::string>::iterator itr = orders.begin(); itr != orders.end(); ++itr) {
        std::cout << *itr << std::endl;
    }

    getchar();
}

虽然上面的代码工作,但效率不高,因为每次删除项目时都会从vector的起点开始。

有更好的方法吗?

6 个答案:

答案 0 :(得分:10)

是;你可以使用自定义谓词的擦除/删除习语:

template <typename SetT>
struct not_contained_in_set_impl
{
    not_contained_in_set_impl(const SetT& s) : set_(s) { }

    template <typename T>
    bool operator()(const T& v)
    {
        return set_.find(v) == set_.end();
    }

    const SetT& set_;
};

template <typename SetT>
not_contained_in_set_impl<SetT> not_contained_in_set(const SetT& s)
{
    return not_contained_in_set_impl<SetT>(s);
}

用作:

orders.erase(
    std::remove_if(orders.begin(),
                   orders.end(),
                   not_contained_in_set(erase_if_not_found)), 
    orders.end());

[在我脑海中编写]

如果您愿意首先对范围进行排序,那么您可以选择其他可能更好的选项(例如std::set_intersection)。

答案 1 :(得分:2)

是的,还有更好的方法 - 您可以在向量的末尾移动要删除的项目。然后在循环结束后剪切向量的结尾。

答案 2 :(得分:1)

我建议将要保留的元素复制到另一个向量中,而不是在每次删除后从头开始再次解析向量。 此外,如果在循环中不再修改集合,则应将end()方法返回的迭代器存储在循环之外,因为对于某些STL实现,调用end()代价很高。一些编译器正在优化它,但并非总是如此。

答案 3 :(得分:0)

首先对矢量进行排序可能会有所帮助,因为集合本身是有序的。 一个变体可以是通过在集合中存在来对矢量进行排序,然后一次性切割所有项目。

答案 4 :(得分:0)

我不确定你要求的是两个向量的交叉点,但如果有,你可以查看std::set_intersection

它需要排序的矢量。

答案 5 :(得分:0)

算法remove_if()会执行此操作,但您需要一个谓词来确定该项目是否不在您的集合中。

您还可以使用remove_copy_if()将项目复制到新的矢量中。

如果您的矢量已排序,则可以使用set_intersection。这也只允许每个找到的元素的一个副本。