Удаление дубликатов элементов с помощью функции «удалить» - PullRequest
0 голосов
/ 24 февраля 2020

Я пытался удалить дубликаты элементов из вектора с помощью функции 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 ]

2 голосов
/ 24 февраля 2020

Первая проблема в вашем коде состоит в том, что вы передаете вектор по значению, а не по ссылке на vectorremove. Вам нужно изменить это значение на

void vectorremove(vector<string>& v);

Тогда внутри вашей функции vectorremove возникнут другие проблемы. vector::erase может сделать недействительными все итераторы, поэтому вы должны включить remove внутри l oop и выполнить erase после l oop.

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());
}
0 голосов
/ 24 февраля 2020

Вы изменяете только копию вектора, вам нужно передать по ссылке, чтобы изменить фактический вектор, поэтому вы не используете auto вместо std :: vector :: iterator. и вы должны знать, что erase делает недействительными все итераторы, указывающие на стертый элемент и за его пределы, сохраняйте действительность итератора, используя возвращаемое значение erase, также используйте std :: getline внутри l oop для хранения значения из 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';
}

}
0 голосов
/ 24 февраля 2020

Сначала вы передаете std::vector по значению, а не по ссылке. Поэтому любые изменения, сделанные вами в функции vectorremove, не будут видны в main. Кроме того, std::vector::erase может сделать недействительными итераторы, поэтому вы не должны использовать его внутри l oop.

Ваш код может выглядеть следующим образом:

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());
}

Обратите внимание на использование авто вместо std::vector<std::string>::iterator.

Однако STL предоставляет удобные функции для достижения того, что вы хотите. Одним из них является std::unique, который

Исключает все элементы, кроме первого, из каждой последовательной группы эквивалентных элементов из диапазона [first, last) и возвращает past-the конец итератора для нового логического конца диапазона.

Чтобы удалить дубликаты из 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 с.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...