Удалить дубликаты в двух векторах на основе дубликатов в первом векторе

У меня есть два вектора, которые связаны между собой. Векторы имеют одинаковый размер, и их содержимое совпадает 1:1 в том смысле, что он может быть рефакторингом в один вектор некоторой структуры. Я пытаюсь удалить дубликаты в первом векторе, и это должно совпадать во втором векторе.

v1 = [5 4 3 7 6 5 2 3]
v2 = [0 1 2 3 4 5 6 7]

Поскольку 5 и 3 повторяются в v1, результат должен быть

v1 = [5 4 3 7 6 2]
v2 = [0 1 2 3 4 6]

Порядок может быть изменен, пока отношение остается прежним.

Я пытаюсь добиться этого, используя библиотеку range-v3.

std::vector<unsigned int>  v1;
std::vector<double> v2;

auto v1Andv2 = range::views::zip(v1, v2);
ranges::sort(v1Andv2)
// ranges::unique(v1Andv2) // Doesnt compile
auto lastIt = std::unique(std::begin(v1Andv2), std::end(v1Andv2), [](const auto &a, const auto &b) {
    // Since the second value of the zip is a double and could be slightly different, 
    // I am only interested in first one
    return std::get<0>(a) == std::get<0>(b);
});

v1.erase(???, std::end(v1));
v2.erase(???, std::end(v2));

Я понятия не имею, что я должен положить в ??? чтобы получить итератор каждого значения в zip. Кроме того, почему ranges::actions::unique не работает в этом случае?


person jjcasmar    schedule 20.04.2020    source источник


Ответы (1)


Проблема, с которой вы столкнулись, заключается в том, что вы не можете sort или иным образом изменить файл view. Если вы просто создадите вектор пар, то вы можете без проблем использовать sort и unique:

auto vv = ranges::views::zip(v1, v2) | 
          ranges::to<std::vector<std::pair<int,int>>>;

vv |= ranges::actions::sort([](auto const &a, auto const &b)
                            { return a.first < b.first; })
    | ranges::actions::unique([](auto const &a, auto const &b)
                              { return a.first == b.first; });

Вот рабочая демонстрация.

Вы даже можете переставить его обратно в исходный порядок, снова sorting, например:

vv |= ranges::actions::sort([](auto const &a, auto const &b)
                            { return a.first < b.first; })
   | ranges::actions::unique([](auto const &a, auto const &b)
                             { return a.first == b.first; })
   | ranges::actions::sort([](auto const &a, auto const &b)
                           { return a.second < b.second; });

Вот демонстрация.

person cigien    schedule 20.04.2020
comment
с помощью boost::zip_iterator это (сортировка + уникальность) должно работать из коробки без создания промежуточного контейнера, не так ли? - person jjcasmar; 21.04.2020
comment
Я не уверен, как это делает boost, но обычно представление не хранится в памяти, и вам нужно, чтобы элементы были в памяти, чтобы выполнить сортировку. - person cigien; 21.04.2020
comment
Это меня смущает. Если вы думаете об итераторах, вы можете иметь пару итераторов, по одному для каждого контейнера, и выполнять те же операции, что и с первым итератором, ко второму. Я бы ожидал, что почтовый индекс будет работать таким образом - person jjcasmar; 21.04.2020
comment
Я не уверен на 100%, но я только что попробовал вашу версию, и, по крайней мере, range-v3 так не работает. - person cigien; 21.04.2020
comment
Итак, у вас есть тест для сортировки диапазона просмотра, и он дает неверные результаты? это странно, здесь он дает хорошие результаты :-s - person jjcasmar; 21.04.2020
comment
Хорошо, но это должен быть другой вопрос, может быть? - person cigien; 21.04.2020
comment
да, давайте вернемся к исходному вопросу. Имея итератор для объекта представления, как мне получить его внутренние итераторы? что-то вроде этого (но на самом деле работает) auto it = std::begin(view(v1,v2)); ++это; это[0], это[1] - person jjcasmar; 21.04.2020