web-dev-qa-db-ja.com

C ++ std ::ペアのベクトルを変換->最初から新しいベクトルに変換

少し初心者の質問でごめんなさい。ベクトルとペアのベクトルがあります

typedef std::vector <int> TItems;
typedef std::vector < std::pair <int, int> > TPairs;

ペアのすべての最初のアイテムを1つのステップで別のベクトルに変換する方法はありますか

int main ()
{
TItems items;
TPairs pairs;

pairs.Push_back (std::make_pair(1,3));
pairs.Push_back (std::make_pair(5,7));

std::transform( items.begin(), items.end(), items.begin(), comp ( &pairs ) );

return 0;
}

ファンクターを設計する方法は?

class comp
{
private:
     TPairs *pairs;

public:
    comp ( TPairs  *pairs_ ) : pairs ( pairs_) { }

    unsigned int operator () ( const unsigned int index ) const
    {
        return  (*pairs)[index].second != pairs->end();  //Bad idea
    }
};

ラムダ式とループのない、もっとユーザーフレンドリーなメソッドがあるかもしれません。ご協力いただきありがとうございます。

19
justik

std::getはすでにライブラリ関数として提供されているので、ファンクターとして使ってほしいです!!

この行を書けたらいいのではないでしょうか!?

std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);

...しかし、それよりも少しひどいです。どのgetを使用するかを明確にする必要があります。

int main() {
  std::vector<int> items;
  std::vector<std::pair<int, int>> pairs;

  pairs.Push_back(std::make_pair(1, 3));
  pairs.Push_back(std::make_pair(5, 7));

  std::transform(pairs.begin(), pairs.end(), std::back_inserter(items),
                 (const int& (*)(const std::pair<int, int>&))std::get<0>);

  return 0;
}

問題は、std::getオーバーロードされている 1。pair&、2。const pair&、および3. pair&&をパラメーターとして使用するため、入力としてあらゆる種類のペアで機能します。残念ながら、オーバーロードはstd::transformのテンプレート型の推定の邪魔になるため、元の行

std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);

収量

 error: no matching function for call to ‘transform(std::vector<std::pair<int, int> >::iterator, std::vector<std::pair<int, int> >::iterator, std::back_insert_iterator<std::vector<int> >, <unresolved overloaded function type>)’
   std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);
                                                                                    ^
...

/usr/include/c++/4.8/bits/stl_algo.h:4915:5: note:   template argument deduction/substitution failed:
 note:   couldn't deduce template parameter ‘_UnaryOperation’
   std::transform(pairs.begin(), pairs.end(), std::back_inserter(items), std::get<0>);

std::getのテンプレートを推測するときに、どのstd::transformのオーバーロードを要求しているかがわからないため、手動で指定する必要があります。関数ポインタを正しい型にキャストすると、コンパイラは「getconst&を取りconst&を返すオーバーロードを使用してください!」と伝えます。

しかし、少なくとも私たちは標準ライブラリコンポーネントを使用しています(イェーイ)?

そして、行数に関しては、他のオプションよりも悪くはありません: http://ideone.com/6dfzxz

7
NHDaly

まず、 back_insertertransform の3番目の引数として使用して、変換された値がの後ろにプッシュされるようにする必要があります。ベクター。

次に、intのペアを取り、最初のintを返すある種のファンクターが必要です。これは行う必要があります:

int firstElement( const std::pair<int, int> &p ) {
    return p.first;
}

さて、ピースをまとめるには:

TPairs pairs;
pairs.Push_back( std::make_pair( 1, 3 ) );
pairs.Push_back( std::make_pair( 5, 7 ) );

TItems items;
std::transform( pairs.begin(), pairs.end(), std::back_inserter( items ),
                firstElement );

このコードの後、itemsには1と5が含まれます。

18
Frerich Raabe

c ++ 03に関するfrerichまたはkotlinskiの回答を参照してください。

ラムダを使用したC++ 11ソリューション:

std::transform(pairs.begin(), 
               pairs.end(), 
               std::back_inserter(items), 
               [](const std::pair<int, int>& p) { return p.first; });
13
stefaanv

これはどう?

items.reserve(pairs.size());
for (size_t it = 0; it < pairs.size(); ++it) {
    items.Push_back(pairs[it].first);
}

理解とデバッグが簡単です。

3
Johan Kotlinski

std::bindを使ってみませんか?

std::transform(pairs.begin(), 
               pairs.end(), 
               std::back_inserter(items), 
               std::bind(&TPairs::value_type::first, std::placeholders::_1));

(C++ 11以外のコードの場合は、std::bindboost::bindに置き換えます)

2
small_duck

c ++ 11からの別の可能性は std::mem_fn であり、これはstd::bindを使用したソリューションに似ています。

std::transform(pairs.begin(), 
               pairs.end(), 
               std::back_inserter(items), 
               std::mem_fn(&std::pair<int,int>::first)               
);
1
Z.C. Tang