一尘不染

使用boost或STL对C ++中的压缩(锁定)容器进行排序

algorithm

我想做什么: 我想对锁定在一起的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_iteratorboost::zip_range(带有boost:: combine range),但是std :: sort和boost :: range :: algorithm ::
sort都
抱怨迭代器/范围是只读的而不是随机访问…

问题:
如何在锁定步骤(压缩)中对N个向量进行排序?这个问题看起来很普通而且很常见,所以我想必须通过一个可能非常复杂的库找到一个简单的解决方案,但是我只是找不到它…

备注: 是的,中也有类似的问题,这个问题经常以不同的形式被问到。但是,它们始终使用以下答案之一关闭:

  • 将向量复制到对/元组中并对该元组进行排序…
  • 将向量复制到每个向量只有一个成员的结构中,并对结构的向量进行排序…
  • 为您的特定问题实现自己的排序功能…
  • 使用索引的辅助数组…
  • 使用boost :: zip_iterator而不使用示例或示例会产生不良结果。

提示:

  • 我在boost邮件列表中找到了该主题,该主题指向Anthony Williams的这篇论文。尽管这似乎仅适用于配对,但他们也讨论了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(不需要)。


阅读 250

收藏
2020-07-28

共1个答案

一尘不染

这是一个基于 range-v3
库的工作示例,该库已提出标准化要求

#include <range/v3/all.hpp>
#include <iostream>

using namespace ranges;

int main() 
{
    std::vector<int> a1{15, 7, 3,  5};
    std::vector<int> a2{ 1, 2, 6, 21};
    sort(view::zip(a1, a2), std::less<>{}, &std::pair<int, int>::first); 
    std::cout << view::all(a1) << '\n';
    std::cout << view::all(a2) << '\n';
}
2020-07-28