ペアのコンテナ内のペア要素の反復処理(C ++)
-
10-07-2019 - |
質問
各要素がvector
であるコンテナ(list
、std::pair
など)がある場合、各ペアの各要素を反復処理する簡単な方法はありますか?
i.e。
std::vector<std::pair<int,int> > a;
a.push_back(std::pair(1,3));
a.push_back(std::pair(2,3));
a.push_back(std::pair(4,2));
a.push_back(std::pair(5,2));
a.push_back(std::pair(1,5));
その後、値1,3,2,3,4,2,5,2,1,5を反復処理できますか?
同様に、上記のペア要素のフラットなリストを持つコンテナ(同じタイプの)を返すファンクタ/関数のタイプは何ですか?
解決
ペアのコンテナーを2番目のコンテナーにフラット化するには、独自のインサーターを作成することもできます。
template<class C>
struct Inserter {
std::back_insert_iterator<C> in;
Inserter(C& c) : in(c) {}
void operator()(const std::pair<typename C::value_type, typename C::value_type>& p)
{
*in++ = p.first;
*in++ = p.second;
}
};
template<class C>
Inserter<C> make_inserter(C& c)
{
return Inserter<C>(c);
}
// usage example:
std::list<int> l;
std::for_each(a.begin(), a.end(), make_inserter(l));
他のヒント
最初に、独自のイテレータクラスを作成する必要があります。これは、ペア内の位置を示すフラグとcontainer<pair>
イテレータをペアにします
2つ目は簡単です。ただし、必要なだけ一般的(同じタイプのコンテナー)にするには、テンプレートtypedef 。ここにベクターのみを示します:
template <class V>
std::vector<V> flatten_pairs(std::vector<std::pair<V,V> > const& a) {
typedef std::vector<std::pair<V,V> > A;
std::vector<V> ret;
for (typename A::const_iterator i=a.begin(),e=a.end();i!=e;++i) {
ret.push_back(i->first);
ret.push_back(i->second);
}
return ret;
}
テンプレートtypedefを偽造する方法は次のとおりです。
template <class C>
struct same_container;
template <class V>
struct same_container<std::vector<V> > {
template <class W> struct rebind { typedef std::vector<W> type; };
};
template <class V>
struct same_list<std::list<V> > {
template <class W> struct rebind { typedef std::list<W> type; };
};
template <class C>
typename same_container<C>::rebind<typename C::value_type::first_type>::type
flatten_pairs(C const& a);
次のコードは、必要に応じてすべての値を出力します:
for ( size_t x = 0; x < a.size(); ++x ) {
cout << a[x].first << "," << a[x].second << ",";
}
カスタムイテレータを作成するよりも、この簡単な方法の方が好きです。
必要な反復を実行する簡単な方法はありませんが、boost :: iterator_adaptorライブラリを確認するか、独自のイテレータを実装して実行することをお勧めします(複雑すぎてはいけません)。次に、2番目の質問で、std :: copyを新しいイテレーターアダプターで使用できます。
いいえ、本当にstd::pair
にはそんなことはありません。代わりにBoost Tupleの使用を検討することをお勧めします。タプルは<=>の拡張バージョンに少し似ており、任意の数の要素(ある程度の制限はありますが、通常は少なくとも10)を許可し、要素へのアクセスもベクトル/配列のようなもの(つまり、名前またはインデックスのいずれかで要素にアクセスできます)。
TR1には、Boostのタプルのサブセットであるstd :: tr1 :: tupleも含まれていますが、メモリが提供される場合、要求している名前/インデックス機能が含まれています。
編集:どちらの場合でも、インデックス表記にはインデックスに compile-time 定数が必要なので、(実行時)ループを記述して要素を反復処理することはできません。タプル-しかし、あなたは少しのメタプログラミングで仕事をすることができます。 Boost Fusionには、必要なものをサポートするためのかなりの部分が含まれています(奇妙な偶然の一致により、タプルはFusionライブラリの一部です)。
ある時点で、独自のイテレータクラスを作成する場合でも、 first および second を使用する必要があります。 (少なくとも、ポータブルな方法で)そこから抜け出す方法はないと思います。