我想做的事:我想对锁定在一起的 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
我现在是怎么做的:我已经实现了自己的快速排序,其中我传递的第一个数组用于比较,排列应用于所有其他数组。我只是不知道如何为我的问题重用 std::sort (例如提取排列)。
我尝试过: boost::zip_iterator和boost::zip_range(带有 boost::combine 范围),但 std::sort 和boost::range::algorithm::sort 都抱怨迭代器/范围是只读的而不是随机访问...
问题:如何在锁步(压缩)中对 N 个向量进行排序?这个问题看起来非常通用和普遍,所以我想必须通过一个可能非常复杂的库来简单地解决它,但我就是找不到它......
备注:是的,stackoverflow 中有类似的问题,这个问题以不同的形式被问到很多。但是,它们总是以以下答案之一关闭:
- 将您的向量复制到一对/元组中并对该元组进行排序...
- 将向量复制到每个向量一个成员的结构中,并对结构向量进行排序...
- 针对您的特定问题实现您自己的排序功能...
- 使用索引的辅助数组...
- 使用 boost::zip_iterator 没有示例或带有产生不良结果的示例。
提示:
- 我在指向Anthony Williams的这篇论文的boost 邮件列表中找到了这个线程。虽然这似乎只适用于对,但他们也讨论了一个 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 支持 BidirectionalIterators(不支持)。