如果元素id与搜索参数匹配,如何从std :: vector中删除元素

时间:2015-10-13 16:53:23

标签: c++ vector smart-pointers

如果项目ID与参数匹配,我试图编写一个算法来搜索并从项目向量中删除项目。请参阅下面的示例代码:

struct item{
    item(int newID){id = newID;}
    bool operator==(const item& other){return id = other.id;}
    int id
};

std::vector<std::unique_ptr<item>> vec;

vec.push_back(std::unique_ptr<item>(new item(10));
vec.push_back(std::unique_ptr<item>(new item(15));
vec.push_back(std::unique_ptr<item>(new item(20));

所以,使用上面的代码,我希望能够搜索存储值15的项目,并将其从向量中删除,删除它。

我将如何做到这一点?

不可否认,我可能也需要使用独特的指针,所以如果我的语法不正确,请随时纠正我。

我尝试过的一些解决方案如下:

void remove_item(int id){
    vec.erase(
               std::remove_if(
                               vec.begin(),
                               vec.end(),
                               [](const item& e){
                                     return id==e.id;
                               }),
               vec.end()
              );

上面的代码产生一个错误,指出变量id不是lambda表达式的捕获列表的一部分。

其次,我尝试过:

void remove_item(item e){
    auto iter = std::find(vec.begin(), vec.end(), e);
    vec.erase(iter);
}

在这种情况下,上面的代码会在==运算符成员函数中产生类型不匹配错误。

4 个答案:

答案 0 :(得分:3)

您需要将id添加到lambda的捕获列表中,以便它可以访问它。然后你需要将传递给lambda的类型设为*vec.begin()的类型std::unique_ptr<item>而不是item

void remove_item(int id){
    vec.erase(
               std::remove_if(
                               vec.begin(),
                               vec.end(),
                               [id](const std::unique_ptr<item>& e){
                                     return id==e->id;
                               }),
               vec.end()
              );
}

从您的代码中删除所有其他无关的错误,您将拥有类似的内容:

struct item {
    item(int newID) { id = newID; }
    bool operator==(const item& other) { return id == other.id; } // == here not =                                          
    int id;
};

std::vector<std::unique_ptr<item>> vec;

void remove_item(int id) {
    vec.erase(std::remove_if(
        vec.begin(), vec.end(), [id](const std::unique_ptr<item>& e) 
                                    {   return id == e->id; })
        ,vec.end());
}

int main()
{
    vec.push_back(std::unique_ptr<item>(new item(10))); // was missing a close paren
    vec.push_back(std::unique_ptr<item>(new item(15))); // was missing a close paren
    vec.push_back(std::unique_ptr<item>(new item(20))); // was missing a close paren
    remove_item(15);
    for (const auto & e : vec)
        std::cout << e->id << " ";
}

Live Example

答案 1 :(得分:2)

使用删除 - 删除习语:

// search for this value
const int val = 15;

// use lambda capture to get "val" into lambda
auto lambda = [val] (const std::unique_ptr<item> & a) { return a->id == val;};

// use remove-erase idiom
auto rem = std::remove_if(vec.begin(), vec.end(), lambda);
vec.erase(rem, vec.end());

答案 2 :(得分:0)

正如Fred Larson所说,你应该使用“erase remove_if”这个成语。 例如:

std::vector<std::unique_ptr<item>> vec;
vec.push_back(std::make_unique<item>(10));
vec.push_back(std::make_unique<item>(15));
vec.push_back(std::make_unique<item>(20));
vec.erase(std::remove_if(vec.begin(), vec.end(),
  [](std::unique_ptr<item> const& item) -> bool { return item->id > 10; }), vec.end());
std::cout << vec.size(); // Output will be 1

答案 3 :(得分:0)

首先,我想说的是,而不是使用push_back&amp; insert,更喜欢emplace_back&amp; emplace C++ containers。我之所以这样说是因为而不是这样写: -

vector<unique_ptr<item>> v;
v.push_back(unique_ptr<item>(new item(5));

您可以这样做: -

vector<unique_ptr<item>> v;
v.emplace_back(new item(5));

其次,您需要知道是否要删除值15的“一个项目”或“所有项目”。这是因为对于前者,您需要使用find_if而对于第二种情况,您应该使用remove_if。您也可以在第一种情况下使用remove_if(但在第二种情况下不使用find_if)但是不建议使用remove_if移位第一种情况下不需要的元素案件。加号find_if只是将迭代器返回到条件首次匹配的项目。因此,选择是你的和明智地使用它。

代码如下: -

// find_if
#include <iostream>
#include <memory>
#include <vector>
#include <algorithm>
using namespace std;

struct item
{
    int x;
    item(){}
    item(int x)
    {
        this->x=x;
    }
};

int main()
{
    vector<unique_ptr<item>> v;
    v.emplace_back(new item(15));
    v.emplace_back(new item(5));
    v.emplace_back(new item(7));
    v.emplace_back(new item(15));
    v.emplace_back(new item(27));
    v.emplace_back(new item(15));
    v.emplace_back(new item(80));

    cout<<"deleting the item storing value 15...\n";
    auto itr = find_if(v.begin(), v.end(), [](unique_ptr<item> &u)     // you cant copy two `unique_ptr` as they can always be `moved & not copied`, hence we are `passing them by reference`
    {
        return (u->x==15);
    });
    v.erase(itr);    // as you need to remove only one item so specify the `iterator` pointing to the required item in `erase`

    for (auto &u:v)  see the use of `reference` again as without it the compiler throws error messages
    {
        cout<<u->x<<" ";
    }
    return 0;
}

输出将是: -

deleting the item storing value 15...
5 7 15 27 15 80

对于remove_if,您只需要进行以下修改: -

auto itr = remove_if(v.begin(), v.end(), [](unique_ptr<item> &u)
    {
        return (u->x==15);
    });
    v.erase(itr,v.end());    // as you need to delete a range of items so you need to specify a range (here `itr` to `v.end()`) in `erase`

此处的输出将为: -

deleting the items storing value 15...
5 7 27 80

现在我想你的怀疑会得到很好的清理!!!