С++: как обнаружить дубликаты в векторной строке и распечатать ОДНУ копию?

Я новичок в С++. Мне было интересно, как я могу найти повторяющиеся строки в векторе и распечатать ОДНУ копию строки. Например, если бы у меня было ‹"кошка", "собака", "собака", "птица">, это напечатало бы кошку, собаку, птицу. Я отсортировал свой вектор и использую функцию смежных_находок и перебираю вектор (поскольку мне нужно найти, дублируется ли какое-либо слово). Мой код обнаруживает дубликаты, но печатает только не дубликаты. Я хотел бы изменить его, чтобы распечатать все не дубликаты, а также только ОДИН из дубликатов, чтобы распечатать все строки в векторе. Вот код, который у меня есть до сих пор:

public: void print(vector<string> in) // print method for printing a vector and it's key
{ 

  sort(in.begin(), in.end()); // sort the vector alphabetically first

  vector<string>::iterator it; 

      for( it = in.begin(); it != in.end(); it++ ) // iterate through it


             if(adjacent_find(in.begin(), in.end()) == in.end()) // don't print duplicates


             cout << *it<<endl; // and print out each string in the vector
}

person user2016393    schedule 27.01.2013    source источник
comment
Уверены, что вам не нужно что-то, что не хранит дубликатов? Если вы этого не сделаете, вы можете использовать std::unique_copy, чтобы скопировать их для вывода.   -  person chris    schedule 28.01.2013
comment
Следуя ответу Криса, например std::set<>   -  person WhozCraig    schedule 28.01.2013


Ответы (3)


Вы можете использовать алгоритмы STL std::unique() или std::unique_copy(). Они работают с любым контейнером STL, а не только с векторами.

Простой пример вывода вектора на стандартный вывод:

#include <iostream>
#include <algorithm>
#include <iterator>

using namespace std;

int main()
{
    vector<string> v = { "hello", "hello", "world" };
    unique_copy(begin(v), end(v), ostream_iterator<string>(cout, " "));
}

Если вы хотите выполнить эту операцию на месте, вы можете использовать std::unique(). Важно иметь в виду, что эта функция физически не удаляет лишние элементы, а возвращает итератор на новый логический конец коллекции:

#include <iostream>
#include <algorithm>
#include <iterator>

using namespace std;

int main()
{
    vector<string> v = { "hello", "hello", "world" };
    auto newEnd = unique(begin(v), end(v));
    for_each(begin(v), newEnd, [] (string const& s) { cout << s << " "; });
}
person Andy Prowl    schedule 27.01.2013
comment
Если вы делаете вектор уникальным на месте, я бы предпочел использовать идиому стирания-удаления вместо сохранения моей конечной позиции. - person chris; 28.01.2013
comment
@chris: я думаю, делать обобщенные утверждения здесь рискованно, это зависит от того, какую обработку вам придется выполнять после. Но да, здравый смысл подсказывает, что вы, скорее всего, захотите позвонить erase() - person Andy Prowl; 28.01.2013
comment
Да, я предполагал, что он будет использоваться немного больше после этого. - person chris; 28.01.2013
comment
Спасибо огромное!! это именно то, что я искал. - person user2016393; 28.01.2013

Попробуйте std::unique, который удаляет все элементы, кроме первого, из каждой последовательной группы идентичных элементов (дополнительные примеры + информация здесь). Поскольку ваш вектор отсортирован, это звучит как то, что вам нужно.

person limes    schedule 27.01.2013

Если ваш вектор уже отсортирован, вы можете использовать std::unique для удаления последовательных дубликатов.

Другой альтернативой является создание std::set из вектора. Это будет иметь уникальные элементы по дизайну.

person juanchopanza    schedule 27.01.2013