21

抱歉有点初学者问题。有向量和向量对

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

有什么方法可以一步将所有第一项成对转换为另一个向量

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

也许有一些更用户友好的方法,没有 lambda 表达式和循环。谢谢你的帮助。

4

6 回答 6

22

首先,您应该使用 aback_inserter作为第三个参数,transform以便将转换后的值推到向量的后面。

其次,您需要某种函子,它接受一对整数并返回第一个整数。这应该这样做:

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。

于 2012-02-01T10:31:42.987 回答
16

请参阅 frerich 或 kotlinski 对 C++03 的回答。

带有 lambda 的 C++11 解决方案:

std::transform(pairs.begin(), 
               pairs.end(), 
               std::back_inserter(items), 
               [](const std::pair<int, int>& p) { return p.first; });
于 2012-02-01T10:49:49.307 回答
10

我真的希望你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,因此您必须手动指定它。将函数指针转换为正确的类型会告诉编译器,“嘿,请使用get带 aconst&并返回 a的重载const&!”

但至少我们使用的是标准库组件(耶)?

就行数而言,它并不比其他选项差:http: //ideone.com/6dfzxz

于 2015-08-14T01:18:19.073 回答
3

这个怎么样?

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

易于理解和调试。

于 2012-02-01T10:22:19.727 回答
3

怎么用std::bind

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

std::bind(替换boost::bind为非 C++11 代码)

于 2012-02-01T10:39:26.380 回答
2

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)               
);
于 2018-12-03T17:17:52.290 回答