C++ std::transform vector of pairs->first to new vector

前端 未结 6 2096
你的背包
你的背包 2020-12-31 00:51

Sorry for a little bit beginner question. There are vector and vector of pairs

typedef std::vector  TItems;
typedef std::vector < std::pair <         


        
相关标签:
6条回答
  • 2020-12-31 01:31

    I really want you to use std::get as the functor, because it's already provided as a library function!!

    Wouldn't it be great if we could write this line!?

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

    ... But it's a bit more terrible than that. You need to disambiguate which get to use:

    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;
    }
    

    The problem is, std::get is overloaded to take 1. pair&, 2. const pair&, and 3. pair&& as the parameters, so that it will work for any sort of pair as input. Unfortunately, the overloads get in the way of the template type deduction for std::transform, so our original line

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

    yields

     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>);
    

    It doesn't know which overload of std::get you are asking for when deducing the template for std::transform, so you have to specify it manually. Casting the function pointer to the right type tells the compiler, "Hey, please use the overload where get takes a const& and returns a const&!"

    But at least we're using standard library components (yay)?

    And in terms of number of lines, it's no worse than the other options: http://ideone.com/6dfzxz

    0 讨论(0)
  • 2020-12-31 01:32

    First of all, you should use a back_inserter as the third argument to transform so that the transformed values are pushed to the back of the vector.

    Second, you need some sort of functor which takes a pair of ints and returns the first one. This should do:

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

    Now, to put the pieces together:

    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 );
    

    After this code, items contains 1 and 5.

    0 讨论(0)
  • 2020-12-31 01:38

    see frerich's or kotlinski's answer for C++03.

    C++11 solution with lambda:

    std::transform(pairs.begin(), 
                   pairs.end(), 
                   std::back_inserter(items), 
                   [](const std::pair<int, int>& p) { return p.first; });
    
    0 讨论(0)
  • 2020-12-31 01:42

    How about using std::bind?

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

    (Replace std::bind by boost::bind for non-C++11 code)

    0 讨论(0)
  • 2020-12-31 01:56

    How about this?

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

    Simple to understand and debug.

    0 讨论(0)
  • 2020-12-31 01:57

    another possibility from C++11 would be std::mem_fn, which is similar to solution with std::bind:

    std::transform(pairs.begin(), 
                   pairs.end(), 
                   std::back_inserter(items), 
                   std::mem_fn(&std::pair<int,int>::first)               
    );
    
    0 讨论(0)
提交回复
热议问题