我想将与谓词(等于整数)匹配的值从map<string,int>
复制到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 ) );
}
);
}
来自g ++ 4.6.1的错误消息是:
error: cannot convert 'std::pair<const std::basic_string<char>, int>' to 'int' in assignment
有没有办法调整示例来执行上述复制?
答案 0 :(得分: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);
}
}
);
。
{{1}}
答案 1 :(得分:12)
使用boost::range
就像:
boost::push_back(
v,
m | boost::adaptors::map_values
| boost::adaptors::filtered([](int val){ return 0 == (val % 2); }));
答案 2 :(得分:5)
编译器错误实际上非常简洁:
error: cannot convert 'std::pair<const std::basic_string<char>, int>' to 'int' in assignment
而这正是问题所在。您要复制的map
具有取消引用pair<KEY,VALUE>
的迭代器,并且无法将pair<KEY,VALUE>
隐式地转换到VALUE
}。
因此,您无法使用copy
或copy_if
从map
复制到vector
;但标准库确实提供了一种可以使用的算法,创造性地称为transform
。 transform
与copy
非常相似,因为它需要两个源迭代器和一个目标迭代器。差异是transform
也采用一元函数来进行实际转换。使用C ++ 11 lambda,您可以将map
的全部内容复制到vector
,如下所示:
transform( m.begin(), m.end(), back_inserter(v), [] (const MyMap::value_type& vt)
{
return vt.second;
});
如果您不想复制map
的全部内容,但只有一些元素符合certian标准,该怎么办?很简单,只需使用transform_if
。
你说什么?标准库中没有transform_if
?好吧,你确实有一点意见。令人沮丧的是,标准库中没有transform_if
。但是writing one是一项非常简单的任务。这是代码:
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;
}
正如您所料,使用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);
} );
答案 3 :(得分:2)
我无法理解为什么简单的for循环解决方案不是这个问题的首选方法
for (std::map< std::string, int >::iterator it = m.begin(); it != m.end(); ++it )
{
if ((it->second % 2) == 0)
v.push_back(it->second);
}
除了它使代码更具可读性之外,它的表现更好。我写了一个简单的基准来看看for循环与其他提议的解决方案相比如何执行:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <time.h>
#include <sstream>
int main(int argc, char *argv[])
{
std::map< std::string, int > m;
std::vector<int> v;
// Fill the map with random values...
srand ( time(NULL) );
for (unsigned i=0; i<10000; ++i)
{
int r = rand();
std::stringstream out;
out << r;
std::string s = out.str();
m[s] = r;
}
/////////// FOR EACH ////////////////////
clock_t start1 = clock();
for (unsigned k=0; k<10000; k++)
{
v.clear();
std::for_each( m.begin(), m.end(),
[&v] ( const std::pair< std::string,int > &it ) {
if ( 0 == ( it.second % 2 ) ) {
v.push_back(it.second);
}
}
);
}
clock_t end1=clock();
std::cout << "Execution Time for_each : " << (end1-start1) << std::endl;
/////////// TRANSFORM ////////////////////
clock_t start2 = clock();
for (unsigned k=0; k<10000; k++)
{
v.clear();
std::transform(m.begin(), m.end(), std::back_inserter(v),
[] ( const std::pair< std::string,int > &it )
{
return it.second;
});
v.erase(
std::remove_if(
v.begin(), v.end(), [](const int value){ return (value % 2) != 0; }),
v.end());
}
clock_t end2 = clock();
std::cout << "Execution Time transform : " << (end2-start2) << std::endl;
/////////// SIMPLE FOR LOOP ////////////////////
clock_t start3 = clock();
for (unsigned k=0; k<10000; k++)
{
v.clear();
for (std::map< std::string, int >::iterator it = m.begin(); it != m.end(); ++it )
{
if ((it->second % 2) == 0)
v.push_back(it->second);
}
}
clock_t end3=clock();
std::cout << "Execution Time Simple For Loop : " << (end3-start3) << std::endl;
}
我得到的结果如下:
Execution Time for_each : 7330000
Execution Time transform : 11090000
Execution Time Simple For Loop : 6530000
答案 4 :(得分:2)
std::copy_if
不允许您从一种类型转移到另一种类型,只是为了过滤要复制的内容。
您可以使用std::transform
删除密钥,然后使用std::remove_if
:
std::vector<int> v;
std::transform(m.begin(), m.end(), std::back_inserter(v),
[] ( const std::pair< std::string,int > &it )
{
return it.second;
});
v.erase(
std::remove_if(
v.begin(), v.end(), [](const int value){ return (value % 2) != 0; }),
v.end());
然而,简单的for循环会更有效,更容易阅读。
答案 5 :(得分:0)
据推测,您只想从map
中检索相关值,而不是键。
SGL版本的STL具有select1st
和select2nd
迭代器用于此类任务。
然而,就个人而言,我认为这不应该通过复制完成 - 您正在转换数据,而不是复制数据。因此,我建议使用std::transform
和仿函数来返回对中的第二项。