Что я хочу сделать: Я хочу сортировать 2, или 3, или N векторы, заблокированные вместе, не копируя их в кортеж. То есть, оставляя многословие в стороне, что-то вроде:
vector<int> v1 = { 1, 2, 3, 4, 5};
vector<double> v2 = { 11, 22, 33, 44, 55};
vector<long> v3 = {111, 222, 333, 444, 555};
typedef tuple<int&,double&,long&> tup_t;
sort(zip(v1,v2,v3),[](tup_t t1, tup_t t2){ return t1.get<0>() > t2.get<0>(); });
for(auto& t : zip(v1,v2,v3))
cout << t.get<0>() << " " << t.get<1>() << " " << t.get<2>() << endl;
Это должно выводить:
5 55 555
4 44 444
...
1 11 111
Как я делаю это прямо сейчас: Я реализовал свою собственную quicksort, где первый массив, который я передаю, используется для сравнения, а перестановки применяются ко всем другим массивам. Я просто не мог понять, как повторно использовать std:: sort для моей проблемы (например, перестановки извлечения).
Что я пробовал: boost:: zip_iterator и boost:: zip_range (с boost:: comb range), но и std:: sort и boost:: range:: algorithm:: sort жалуются, что итераторы/диапазоны доступны только для чтения, а не для произвольного доступа...
Вопрос: Как сортировать N векторов в шаге блокировки (zipped)? Проблема выглядит довольно общей и распространенной, поэтому я предполагаю, что должно быть простое решение через, вероятно, очень сложную библиотеку, но я просто не могу ее найти...
Замечания: да, в stackoverflow есть похожие вопросы, этот вопрос задается очень часто в разных формах. Однако они всегда закрываются одним из следующих ответов:
- Скопируйте свои векторы в пару/кортеж и отсортируйте этот кортеж...
- Скопируйте свои векторы в структуру с одним членом на вектор и отсортируйте вектор structs...
- Внедрите свою собственную функцию сортировки для вашей конкретной проблемы...
- Используйте вспомогательный массив индексов...
- Используйте boost:: zip_iterator без примера или с примером, который создает плохие результаты.
Подсказка:
- Я нашел этот поток в расширенный список рассылки, который указывает на это от Энтони Уильямса. Хотя это, похоже, работает только для пар, они также обсуждают TupleIteratorType, но я не смог его найти.
- user673679 нашел этот пост, содержащий хорошее решение для двух контейнер контейнер. Это также устраняет проблему (акцент мой):
[...] Основная проблема заключается в том, что "пары" ссылок на массивы не ведут себя так, как должны [...] Я просто решил злоупотреблять нотацией итератора и писать что-то, что работает. Это связано с тем, что написание, фактически, несоответствующего итератора, где ссылка типа значения не совпадает с эталонным типом.
Ответ: см. комментарий по interjay ниже (это также частично отвечает на вопрос будущего):
#include "tupleit.hh"
#include <vector>
#include <iostream>
#include <boost/range.hpp>
#include <boost/range/algorithm/sort.hpp>
#include <boost/range/algorithm/for_each.hpp>
template <typename... T>
auto zip(T&... containers)
-> boost::iterator_range<decltype(iterators::makeTupleIterator(std::begin(containers)...))> {
return boost::make_iterator_range(iterators::makeTupleIterator(std::begin(containers)...),
iterators::makeTupleIterator(std::end(containers)...));
}
int main() {
typedef boost::tuple<int&,double&,long&> tup_t;
std::vector<int> a = { 1, 2, 3, 4 };
std::vector<double> b = { 11, 22, 33, 44 };
std::vector<long> c = { 111, 222, 333, 444 };
auto print = [](tup_t t){ std::cout << t.get<0>() << " " << t.get<1>() << " " << t.get<2>() << std::endl; };
boost::for_each( zip(a, b, c), print);
boost::sort( zip(a, b, c), [](tup_t i, tup_t j){ return i.get<0>() > j.get<0>(); });
for ( auto tup : zip(a, b, c) ) print(tup);
return 0;
}
Будущий вопрос: предыдущий ответ работает для контейнеров последовательностей. Можем ли мы получить его также для работы с сортируемыми контейнерами (например, последовательностями и списками)? Для этого потребуются random_access и двунаправленные TupleIterators, а также алгоритм сортировки, который работает с двунаправленными итераторами.
Обновление:, это работает для комбинаций последовательноподобных контейнеров. Однако для смешивания списка потребуется, чтобы std:: sort поддерживал двунаправленныеИтераторы (это не так).