使用“删除”功能删除重复的元素

时间:2020-02-24 01:13:55

标签: c++ algorithm vector

我试图使用算法库中的函数vectorremove,通过函数remove从向量中删除重复元素,但这不起作用:

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;

void vectorremove(vector<string> v)
{
    for (vector<string>::iterator it = v.begin(); it != v.end(); ++it)
    {
        vector<string>::iterator end = remove(it + 1, v.end(), *it);
        v.erase(end, v.end());
    }
}

int main()
{
    vector<string> vect;
    string x;

    while (cin >> x)
    {
        vect.push_back(x);
    }

    vectorremove(vect);

    for (vector<string>::iterator it = vect.begin(); it != vect.end(); ++it)
    {
        cout << *it << endl;
    }
    return 0;
}

我编写了这段代码来测试功能vectorremove是否起作用,不幸的是,看来vectorremove对向量没有影响。在remove的定义中使用vectorremove时是否犯了任何错误?

3 个答案:

答案 0 :(得分:2)

代码中的第一个问题是您要通过值而不是通过引用vectorremove来传递向量。您需要将其更改为

void vectorremove(vector<string>& v);

然后在vectorremove函数内部,您还有另一个问题。 vector::erase可以使所有迭代器无效,因此您应在循环内仅使用remove,并在循环后执行erase

void vectorremove(vector<string>& v)
{
    vector<string>::iterator end{ v.end() };
    for (vector<string>::iterator it = v.begin(); it != end; ++it)
    {
        end = remove(it + 1, end, *it);
    }
    v.erase(end, v.end());
}

答案 1 :(得分:0)

首先,您要按值而不是引用传递std::vector。因此,您在vectorremove函数中所做的任何更改都不会在main中可见。 此外,std::vector::erase可能会使迭代器无效,因此您不得在循环内使用它。

您的代码可能如下:

void vectorremove(std::vector<std::string>& v) {
    auto end{ v.end() };
    for (auto it = v.begin(); it != end; ++it)
    {
        end = std::remove(it + 1, end, *it);
    }
    v.erase(end, v.end());
}

请注意使用 auto 代替std::vector<std::string>::iterator

但是,STL提供了方便的功能来实现您想要的功能。其中之一是std::unique

从每个连续的组中消除除第一个元素外的所有元素 [first,last)范围内的等价元素,并返回 范围的新逻辑末端的最新迭代器。

要从std::vector中删除重复项,您可以执行以下操作:

#include <iostream>
#include <algorithm>
#include <vector>

int main()  {
    std::vector<int> v{ 1, 2, 3, 1, 2, 3, 3, 4, 5, 4, 5, 6, 7 };
    std::sort(v.begin(), v.end()); // 1 1 2 2 3 3 3 4 4 5 5 6 7 
    auto last = std::unique(v.begin(), v.end());
    v.erase(last, v.end());
    for (auto const i : v) {
        std::cout << i << " ";
    }
    std::cout << std::endl;

    return 0;
}

请记住,std::unique只能按预期运行仅适用于已排序的 std::vector

答案 2 :(得分:0)

您仅修改vector的副本,必须通过引用来修改实际 向量,为什么不使用auto代替std :: vector :: iterator。而且你必须 知道擦除使指向被擦除元素的所有迭代器无效,并且 除了被擦除的元素之外,还可以通过使用擦除的返回值来保持迭代器有效,还可以在循环内部使用std :: getline来存储std :: cin的值以包含新行。

或者,您可以使用std :: unique删除重复值,并在对元素进行排序后按预期工作。和std :: unique返回结束迭代器,该结束迭代器返回范围的新逻辑结束:-

#include <vector>
#include <algorithm>
#include <string>

std::vector<std::string> removeDuplicate(std::vector<std::string> & v){

std::vector<std::string> vec;

std::sort(std::begin(v), std::end(v));
auto pos = std::unique(std::begin(v), std::end(v));

vec.assign(std::begin(v), pos);
return vec;
}


int main(){

std::vector<std::string> vect{"John", "John", "Paul", "John", "Lucy", "Bob", "Bob"};

auto pureVector = removeDuplicate(vect);

for(auto const & v : pureVector){
    std::cout << v << '\n';
}

}