stdlib "Уникальный" метод не работает - PullRequest
3 голосов
/ 21 сентября 2011

Я пытаюсь использовать алгоритм C ++ Standard Library uniqueBinaryPredicate).

Я создал вектор пар; каждая пара похожа на «(первый = вектор из 4 двойных, второй = целое число)». Второй элемент служит индексом, поэтому после использования `unique, я все еще могу определить исходный индекс.

В приведенном ниже примере я создал что-то вроде этого:


10 20 30 40, 1
10 20 30 40, 2
10 20 30 40, 3
10 20 30 40, 4
10 20 30 40, 5
10 20 30 40, 6

Теперь я хочу использовать уникальную функцию для сравнения только первого элемента каждой пары. Я использовал настраиваемый двоичный предиктор uniquepred. Действительно, это работает, но вектор не уменьшается после использования unique.

ОЖИДАЕМЫЙ РЕЗУЛЬТАТ

Size before=6
equal!
equal!
equal!
equal!
equal!
Size after=1

АКТУАЛЬНЫЙ РЕЗУЛЬТАТ

Size before=6
equal!
equal!
equal!
equal!
equal!
Size after=6

Ниже приведен минимальный рабочий пример. Пожалуйста, помогите мне отладить это.

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

typedef std::vector<double> V1db;
typedef std::pair<V1db, int > Pairs;
typedef std::vector<Pairs> Vpairs;

bool uniquepred( const Pairs& l, const Pairs& r) {
    if (l.first==r.first)
        cout<<"equal!"<<endl;
    return l.first == r.first;
}
int main()
{
    Vpairs ak;
    V1db u2(4);
    u2[0]=10;u2[1]=20;u2[2]=30;u2[3]=40;
    Pairs m2;
    m2.first = u2;
    m2.second= 1;
    ak.push_back(m2);
    m2.second= 2;
    ak.push_back(m2);
    m2.second= 3;
    ak.push_back(m2);
    m2.second= 4;
    ak.push_back(m2);
    m2.second= 5;
    ak.push_back(m2);
    m2.second= 6;
    ak.push_back(m2);
    cout<<"Size before="<<ak.size()<<endl;
    unique(ak.begin(), ak.end(), uniquepred);
    cout<<"Size after="<<ak.size()<<endl;

    return 0;
}

Ответы [ 2 ]

9 голосов
/ 21 сентября 2011

Вы хотите сделать:

ak.erase(unique(ak.begin(), ak.end(), uniquepred), ak.end());

Причина этого в том, что std::unique изменяет порядок значений. Однако он не удаляет их, и у вас остается новый диапазон от begin() до итератора, который возвращает unique. Сам контейнер не изменяется, кроме этого переупорядочения.

Нет метода «удалить в позиции X» для векторов, даже если бы он существовал, это сделало бы недействительными итераторы. Разработанный алгоритм unique даже ничего не знает о базовом контейнере, поэтому он может работать с любой допустимой парой итераторов. Единственное требование - это ForwardIterators.

6 голосов
/ 21 сентября 2011

std::unique работает работает; Вы забыли поискать ее в своей любимой документации библиотеки C ++, чтобы узнать, что она делает.

Он функционирует немного странно, как std::remove, в том смысле, что он на самом деле просто перемещает вещи и дает конечный итератор для нового диапазона. Размер нижележащего контейнера не изменяется: вы должны удалить его самостоятельно:

ak.erase(std::unique(ak.begin(), ak.end(), uniquepred), ak.end());
...