如何将copy_if从map映射到vector?

BЈо*_*вић 9 c++ copy c++11

我想将与谓词(等于整数)匹配的值从a复制map<string,int>到a vector<int>.

这是我试过的:

#include <map>
#include <vector>
#include <algorithm>

int main()
{
    std::vector< int > v;
    std::map< std::string, int > m;

    m[ "1" ] = 1;
    m[ "2" ] = 2;
    m[ "3" ] = 3;
    m[ "4" ] = 4;
    m[ "5" ] = 5;

    std::copy_if( m.begin(), m.end(), v.begin(),
                  [] ( const std::pair< std::string,int > &it )
                  {
                    return ( 0 == ( it.second % 2 ) );
                  }
                  );
}
Run Code Online (Sandbox Code Playgroud)

来自g ++ 4.6.1的错误消息是:

error: cannot convert 'std::pair<const std::basic_string<char>, int>' to 'int' in assignment
Run Code Online (Sandbox Code Playgroud)

有没有办法调整示例来执行上述复制?

Kle*_*ist 12

问题

因为你从复制副本失败的map::iterator它迭代pair<string const,int>vector::iterator它迭代int.

替换copy_if为矢量for_each并对其执行操作push_back.

std::for_each( m.begin(), m.end(),
    [&v] ( std::pair< std::string const,int > const&it ) {
        if ( 0 == ( it.second % 2 ) ) {
            v.push_back(it.second);
        }
    }
);
Run Code Online (Sandbox Code Playgroud)

  • 不要手写循环并用手推回每个元素,而是使用`transform`.这就是它的用途. (3认同)
  • 您需要将lambda capture子句修改为`[&v]`,以便访问封闭范围中的向量. (2认同)

Man*_*rse 12

有了boost::range它就像:

boost::push_back(
    v,
    m | boost::adaptors::map_values 
      | boost::adaptors::filtered([](int val){ return 0 == (val % 2); }));
Run Code Online (Sandbox Code Playgroud)

  • `boost :: range`需要更多的爱.简单的管道概念太好了,无法通过编程. (6认同)
  • boost :: copy + std :: back_inserter非常难看.如果你使用boost.range然后`boost :: push_back(v,m | map_values | filtered([](int val){return 0 ==(val%2);}));`更清晰,更短恕我直言. (2认同)

Joh*_*ing 5

编译器错误实际上非常简洁:

error: cannot convert 'std::pair<const std::basic_string<char>, int>' to 'int' in assignment
Run Code Online (Sandbox Code Playgroud)

而这正是问题所在.在map你从复制具有迭代器解引用的pair<KEY,VALUE>,而且也没有办法隐含变换一个pair<KEY,VALUE>只是一个VALUE.

因此,你不能使用copycopy_if从a复制map到a vector; 但标准库确实提供了一种可以创造性地使用的算法transform. transform非常相似copy,因为它需要两个源迭代器和一个目标迭代器.差异transform还在于实现实际转换的一元函数.使用C++ 11 lambda,您可以将a的全部内容复制mapvector如下:

transform( m.begin(), m.end(), back_inserter(v), [] (const MyMap::value_type& vt)
{
  return vt.second;
});
Run Code Online (Sandbox Code Playgroud)

如果您不想复制整个内容map,但只有一些符合certian标准的元素,该怎么办?简单,只需使用transform_if.

那是什么,你说?transform_if标准库中没有?好吧,你确实有一点意见.令人沮丧的是transform_if,标准库中没有.但写一个是一个足够简单的任务.这是代码:

template<class InputIterator, class OutputIterator, class UnaryFunction, class Predicate>
OutputIterator transform_if(InputIterator first, 
                            InputIterator last, 
                            OutputIterator result, 
                            UnaryFunction f, 
                            Predicate pred)
{
    for (; first != last; ++first)
    {
        if( pred(*first) )
            *result++ = f(*first);
    }
    return result; 
}
Run Code Online (Sandbox Code Playgroud)

正如您所料,使用transform_if就像把copy_if它和它一起捣碎一样transform.这里有一些psudo代码来演示:

transform_if( m.begin(), m.end(), back_inserter(v),
  [] (const MyMap::value_type& vt) // The UnaryFunction takes a pair<K,V> and returns a V
  {
    return vt.second;
  }, [] (const MyMap::value_type& vt) // The predicate returns true if this item should be copied
  {
     return 0 == (vt.second%2);
  } );
Run Code Online (Sandbox Code Playgroud)

  • 它更短.从map-elements到map-values的转换通过命名库调用进行,并且对该转换的结果进行过滤(而不是重复转换).整个代码由简单的正交元素组成,而不是使用单一的`transform_if`函数,它同时执行多个事务.它避免了为单个输入范围指定多个迭代器的需要. (2认同)