уникальные значения в векторе stl - PullRequest
0 голосов
/ 18 мая 2018

У меня есть следующий код, который вычисляет уникальные значения в векторе

bool uniqueCompressVectorCompareFunction (unsigned int num1, unsigned int num2) {
  return (num1 == num2);
}


// redirect input from stream to file.
std::ifstream inputFile("testinput.txt");
std::streambuf* pcurrRdBuf = std::cin.rdbuf();
std::cin.set_rdbuf(inputFile.rdbuf());

unsigned int uiNoOfFishes = 0;
std::cin >> uiNoOfFishes;
std::vector<unsigned int> vecOfLenOfFishes(uiNoOfFishes);
std::vector<unsigned int> vecOfTimeHeadOfFishes(uiNoOfFishes);

// get length of fishes
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++) {
    std::cin >> vecOfLenOfFishes[uiIdx];
}

// get time head of fishes
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++) {
    std::cin >> vecOfTimeHeadOfFishes[uiIdx];
}

std::cout << "Actual input length of fishes: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecOfLenOfFishes.size(); uiIdx++) {
    std::cout << vecOfLenOfFishes[uiIdx] << "   ";
}
std::cout << std::endl;

std::cout << "Actual input time head of fishes: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecOfTimeHeadOfFishes.size(); uiIdx++) {
    std::cout << vecOfTimeHeadOfFishes[uiIdx] << "   ";
}
std::cout << std::endl;


std::vector<unsigned int> vecUniqueInputValues;
// copy length of fishes.
unsigned int uiUniqueVecIdx = 0;
for(; uiUniqueVecIdx < uiNoOfFishes; uiUniqueVecIdx++) {
    vecUniqueInputValues.push_back(vecOfLenOfFishes[uiUniqueVecIdx]);
}

// copy time head of fishes.
for(unsigned int uiIdx = 0; uiIdx < uiNoOfFishes; uiIdx++, uiUniqueVecIdx++) {
    vecUniqueInputValues.push_back( vecOfTimeHeadOfFishes[uiIdx]);
}

// using predicate comparison:
std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), uniqueCompressVectorCompareFunction); 



std::cout << "compressInputData unique values sorted: " << std::endl;
for(unsigned int uiIdx = 0; uiIdx <vecUniqueInputValues.size(); uiIdx++) {
    std::cout << vecUniqueInputValues[uiIdx] << "   ";
}
std::cout << std::endl;

// содержимое в testinput.txt ниже

5
2 4 4 2 4
1 4 1 6 4

Вывод показан ниже

Actual input length of fishes:
2   4   4   2   4
Actual input time head of fishes:
1   4   1   6   4
compressInputData total values:
2   4   4   2   4   1   4   1   6   4
compressInputData unique values sorted:
2   4   2   4   1   4   1   6   4   4

Я ожидаю, что уникальные значения входных данных компрессии должны быть 1 2 4 6

Что такое ошибка в моем коде?

Ответы [ 3 ]

0 голосов
/ 18 мая 2018

С Документы :

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

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

Сортировкавектор перед вызовом std::unique

0 голосов
/ 18 мая 2018

Как указывают другие ответы, std::unique удаляет последовательные дубликаты.Это позволяет использовать его как однопроходный алгоритм.

Если вы хотите удалить непоследовательные дубликаты без изменения порядка оставшихся элементов, вам придется написать другую функцию, чтобы сделать это.Как правило, для этого потребуется несколько проходов в диапазоне ввода.

Вот простая реализация, соответствующая подписи std::unique

template <typename ForwardIterator>
ForwardIterator multipass_unique(ForwardIterator first, ForwardIterator last)
{
    for (; first != last; ++first)
    {
        // Search the whole range for values that are equal to the current
        // Any values removed shorten the range to search
        last = std::remove(std::next(first), last, *first);
    }
    return last;
}

И вариант, который принимает BinaryPredicate

template <typename ForwardIterator, typename BinaryPredicate>
ForwardIterator multipass_unique(ForwardIterator first, ForwardIterator last, BinaryPredicate pred)
{
    for (; first != last; ++first)
    {
        // Search the whole range for values that satisfy the predicate
        // Any values removed shorten the range to search
        last = std::remove_if(std::next(first), last, [=](auto val){ return pred(*first, val); });
    }
    return last;
}
0 голосов
/ 18 мая 2018

Согласно документации std::unique it

[e] ограничивает все элементы, кроме первого, из каждой последовательной группы эквивалентных элементов

(акцент мой).

Таким образом, он не удаляет все повторяющиеся значения, только те, которые находятся рядом, сокращая, например, [1 2 2 3 3 3 1 1 3 3 2 2] до [1 2 3 1 3 2].

Если вы хотите сохранить только уникальные элементы в целомВы должны сначала отсортировать вектор:

std::sort(vecUniqueInputValues.begin(), vecUniqueInputValues.end());

// Vector is now [1, 1, 2, 2, .., 2, 4, .., 4, 5, ... ]

std::unique (vecUniqueInputValues.begin(), vecUniqueInputValues.end(), 
  uniqueCompressVectorCompareFunction); 

Некоторые второстепенные точки

Функция сравнения выглядит несколько избыточной - если вы не укажете ее

[e] элементы сравниваются с использованием operator==.

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

auto endOfUniqueRange = std::unique(...);

std::cout << "compressInputData unique values sorted: " << std::endl;
for(auto& uiIt = vecUniqueInputValues.cbegin(); uiIt != endOfUniqueRange ; ++uiIt) {
    std::cout << *uiIt << "   ";
}
std::cout << std::endl;

На самом деле, я рекомендую использовать итераторы и циклы на основе диапазона в любом случае: вместо

for(auto i = 0; i < myVec.size(); ++i) {
  // Do something with myVec[i]
}

запись

for(auto it = myVec.cbegin(); it != myVec.cend(); ++it) {
  // Do something with *it
}

или, для итерации всего вектора,

for(unsigned int val : myVec) { 
  // Do something with val
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...