やりたいこと: 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 range を使用)、しかし std::sort とboost::range::algorithm::sortの両方が、イテレータ/範囲が読み取り専用であると不平を言うランダムアクセスではありません...
質問:ロック ステップ (zip 形式) で N ベクトルを並べ替えるにはどうすればよいですか? 問題はかなり一般的で一般的なように見えるので、おそらく非常に複雑なライブラリを介した簡単な解決策があるに違いないと思いますが、見つけることができません...
備考:はい、stackoverflow にも同様の質問があります。この質問は、さまざまな形でよく尋ねられます。ただし、それらは常に次のいずれかの回答で閉じられます。
- ベクターをペア/タプルにコピーし、そのタプルをソートします...
- ベクトルをベクトルごとに 1 つのメンバーを持つ構造体にコピーし、構造体のベクトルを並べ替えます...
- 特定の問題に対して独自のソート機能を実装します...
- インデックスの補助配列を使用...
- 例なしでboost::zip_iteratorを使用するか、悪い結果をもたらす例を使用してください。
ヒント:
- Boost メーリング リストでこのスレッドを見つけました。このスレッドは、Anthony Williams のこの論文を示しています。これはペアでしか機能しないようですが、 TupleIteratorType についても議論していますが、見つけることができませんでした。
- user673679は、2 つのコンテナーの場合の優れたソリューションを含むこの投稿を見つけました。それはまた問題を突き止めます(強調は私のものです):
[...] 根本的な問題は、配列参照の「ペア」が本来あるべき動作をしないことです [...] イテレータの表記法を悪用して、機能するものを書くことにしました。これには、事実上、値の型の参照が参照の型と同じではない非準拠のイテレータを書くことが含まれていました。
回答:以下の 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 と双方向 TupleIterator、および双方向イテレータで機能するソート アルゴリズムが必要です。
更新:これは、シーケンスのようなコンテナーの組み合わせで機能します。ただし、リストを混在させるには、std::sort が BidirectionalIterator をサポートしている必要があります (そうではありません)。