如何使用for_each从向量中收集一些信息到另一个向量 [英] how to use for_each to collect some info from a vector into anothervector

查看:38
本文介绍了如何使用for_each从向量中收集一些信息到另一个向量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我对for_each不太熟悉,支持我有一个

向量< pair< unsigned int,unsigned int> > vec1和内容是


{< 0x00000000,0x000000FF>,< 0x10000000,0x2FFFFFFF>}


我想要的是创建另一个矢量,矢量< int> vec2,存储

vec1中整数的前8位头,对于上面的例子,


0x00000000& 0xFF000000 ==> 0x00000000,

0x000000FF& 0xFF000000 ==> 0x00000000,

0x10000000& 0xFF000000 ==> 0x10000000,

0x2FFFFFFF& 0xFF000000 ==> 0x2F000000,


然后vec2应为{0x00000000,0x10000000,0x2F000000}。


专门编写for循环很容易,只是想知道怎么做

使用for_each。


谢谢。

解决方案

< blockquote> John Black写道:

我对for_each不太熟悉,支持我有一个
向量< pair< unsigned int,unsigned int> > vec1和内容是

{< 0x00000000,0x000000FF>,< 0x10000000,0x2FFFFFFF>}
我想要的是创建另一个向量,向量< int> vec2,它存储了vec1中整数的所有前8位头,对于上面的例子,

0x00000000& 0xFF000000 ==> 0x00000000,
0x000000FF& 0xFF000000 ==> 0x00000000,
0x10000000& 0xFF000000 ==> 0x10000000,
0x2FFFFFFF& 0xFF000000 ==> 0x2F000000,
然后vec2应该是{0x00000000,0x10000000,0x2F000000}。

专门写一个for循环很容易,只是想知道怎么做
使用for_each。




你必须实现一个能够做到这一点的仿函数。 Boost库

有一些标准库中没有的机制。

例如,没有简单的仿函数可以提取''first''或''second '

来自一对。


类似于:


struct skim_pairs_to {

vector< int>&收集器;

skim_pairs_to(向量< int>& c):collector(c){}

void operator()(const std :: pair< unsigned,unsigned> & p){

collector.push_back(p.first& 0xff000000);

collector.push_back(p.second& 0xff000000);

}

};


...

std :: for_each(vec1.begin(),vec1。 end(),skim_pairs_to(vec2));


应该这样做。我没有测试代码。


Victor


John Black< bl *** @ eed.com>写道:


我不太熟悉for_each,支持我有一个
向量<对< unsigned int,unsigned int> > vec1和内容是

{< 0x00000000,0x000000FF>,< 0x10000000,0x2FFFFFFF>我想要的是创建另一个向量,向量< int> vec2,它存储了vec1中整数的所有前8位头,对于上面的例子,

0x00000000& 0xFF000000 ==> 0x00000000,
0x000000FF& 0xFF000000 ==> 0x00000000,
0x10000000& 0xFF000000 ==> 0x10000000,
0x2FFFFFFF& 0xFF000000 ==> 0x2F000000,
然后vec2应为{0x00000000,0x10000000,0x2F000000}。


你只在vec2中放了3个项目,那是故意的吗? IE是重复的值

不应该输入?


如果是这种情况,我会首先插入一个集合,然后从

设置为向量(见下文......)


专门编写for循环很容易,只是想知道怎么做
使用for_each。




同样的方式,除了循环体将在仿函数中。所以你可能从
开始:


for(vector< pair< unsigned,unsigned>> :: iterator it = v.begin();

it!= v.end(); ++ it)

{

v2.push_back(it-> first& 0xFF000000 );

v2.push_back(it-> second& 0xFF000000);

}


这将成为:


struct filler {

vector< unsigned>& v;

填充(向量< unsigned>& v):v(v){}

void operator()(const对< unsigned,unsigned>& ; p){

v.push_back(p.first& 0xFF000000);

v.push_back(p.second& 0xFF000000);

}

};


和:


for_each(v.begin(),v.end (),填充(v2));


似乎有点浪费。我们已经创建了一个新类型,在这一个地方只能使用
,当有人遇到''for_each''时他需要搜索b $ b代码来找出这种新类型的作用。


如果我们能够做出更多可恢复的东西,同时做一个更好的表达工作怎么办?在它应该发生的地方发生了什么?


让我们来看看我们在做什么。基本上它是一个变换

,除了第一个容器中的每个值被转换两次并且

放在第二个容器中。所以我们可以用

std :: transform来建模。


模板< typename InputIter,typename OutputIter,

typename Op1,typename Op2>

OutputIter expanding_transform(InputIter first,InputIter last,

OutputIter result,Op1 op1,Op2 op2)

{

while(first!= last)

{

* result ++ = op1 (*第一个);

*结果++ = op2(*第一个);

++优先;

}

返回结果;

}


也许以上不是所有可重用的,但它确实更可靠了

比上面的''填充''类型。例如,我们可以使用此函数

输出我们的向量<对< unsigned,unsigned> >我们已经可以看到这个功能的两个用途,这个事实很好地证明了这个功能。

重新使用。


现在,我们需要将哪些参数传递给此函数?前两个

很容易''v.begin()''和''v.end()''我们在

标准算法中一直看到这个。第三个是有点困难,但仍然经常看到:

''back_inserter(v2)''。当然''v''是我们的矢量<对<未签名,

unsigned> >和''v2''是我们的新矢量< unsigned> ...对于最后两个

参数,我们需要做更多工作。


首先我们检查''功能''部分stl。我们找到了一个

''logical_and''仿函数,但没有''bit_and''。哦,这很容易解决:


模板< typename T>

struct bit_and:public std :: binary_function< T,T,T>

{

T operator()(const T& x,const T& y)const {return x& Ÿ; }

};


因此,对于我们的expanding_transform中的每个Ops,我们需要调用

''bit_and' '第一个参数是

对中的第一个和第二个参数,第二个参数是0xFF000000。让我们制作一个理算,

就是这样:


binder2nd< BIT_AND< unsigned> > high_8_mask =

bind2nd(bit_and< unsigned>(),0xFF000000);


让'确保我们知道high_8_mask的作用:


断言(high_8_mask(0x12345678)== 0x12000000);


不幸的是,我们不能只是通过我们的对< unsigned,unsigned>进入上面的

,因为它只需要一个无符号值。


现在我们必须回顾过去。原始STL有几个有用的

仿函数从未成为标准。其中两个特别是

处理操作对象对象,以便它们可以在

标准仿函数中使用:select1st和select2nd。您可以在SGI的

网站上找到它们,我相信其他网站都有它们。他们都完全按照你的想法行事。你传入一对对象,然后返回

对的第一个或第二个对象。


另一个有用的函子是''unary_compose'';这需要另外两个

仿函数并将它们组合起来:f1(f2(x))。还有一个

有用的函数''compose1''有助于构建一个unary_compose对象(

就像''make_pair''构建''对'对象的方式。你也可以在这里得到这个

,它被称为''compose_f_gx''......


我们的武器库中有这三个仿函数我们可以构建我们的新算法将使用的
的仿函数。


我也想让搭配更容易使用,所以我会制作一个typedef。


现在我将把所有这些放在一起展示它是如何工作的:


typedef pair< unsigned,unsigned> two_flags;


binder2nd< BIT_AND< unsigned> > high_8_mask =

bind2nd(bit_and< unsigned>(),0xFF000000);


expanding_transform(v.begin(),v.end(),back_inserter (v2),

compose1(high_8_mask,select1st< two_flags>()),

compose1(high_8_mask,select2nd< two_flags>()));


你去了,我们用很多小的,高价值的b $ b可重复使用的组件写了循环。


现在回到我上面的问题是没有重复的价值观。如果是这种情况

然后插入一套:


set< unsigned> s;

binder2nd< bit_and< unsigned int> > high_8_mask =

bind2nd(bit_and< unsigned>(),0xFF000000);

expanding_transform(v.begin(),v.end(),

inserter(s,s.begin()),

compose1(high_8_mask,select1st< two_flags>()),

compose1(high_8_mask,select2nd< two_flags >()));

copy(s.begin(),s.end(),back_inserter(v2));


John Black< bl *** @ eed.com>在消息新闻中写道:< 40 *************** @ eed.com> ...


我不熟悉for_each很好,支持我有一个
向量< pair< unsigned int,unsigned int> > vec1和内容是

{< 0x00000000,0x000000FF>,< 0x10000000,0x2FFFFFFF>}
我想要的是创建另一个向量,向量< int> vec2,它存储了vec1中整数的所有前8位头,对于上面的例子,

0x00000000& 0xFF000000 ==> 0x00000000,
0x000000FF& 0xFF000000 ==> 0x00000000,
0x10000000& 0xFF000000 ==> 0x10000000,
0x2FFFFFFF& 0xFF000000 ==> 0x2F000000,
然后vec2应该是{0x00000000,0x10000000,0x2F000000}。

专门写一个for循环很容易,只是想知道怎么做
使用for_each。




IMO,你的步骤不正常。首先你需要选择正确的算法

,然后你需要弄清楚如何使用它。


在这种情况下,std :: transform很多更适合这份工作(

至少IMO)。


//警告:此代码不完整,因此未经测试。

//保存一点输入:

typedef std :: pair< unsigned int,unsigned int> dt;


//定义我们要对每个项目做什么:

struct top8 {

unsigned int operator()(dt const& d){

//假设32位整数。

返回d.first& 0x000000000;

}

};


//定义输入和输出的向量:

的std ::矢量< DT> vec1;

std :: vector< unsigned int> vec2;


//填写vec1的代码就在这里。


//将输入转换为输出:

std :: transform(vec1.begin(),vec1.end(),std :: back_inserter(vec2),

top8);


傲慢的预测:没有人会使用

for_each发布更好的解决方案。 :-)


P.S.当然,我可以定义更好。 < G>


-

后来,

杰瑞。


宇宙是自己想象的虚构。


Hi,
I am not familiar with for_each very well, suppoase I have a
vector<pair<unsigned int, unsigned int> > vec1 and the contents are

{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>}

what I want is to create another vector, vector<int> vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 ==> 0x00000000,
0x000000FF & 0xFF000000 ==> 0x00000000,
0x10000000 & 0xFF000000 ==> 0x10000000,
0x2FFFFFFF & 0xFF000000 ==> 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

It''s easy to specifically write a for loop, just wonder how to do it
use for_each.

Thanks.

解决方案

John Black wrote:

I am not familiar with for_each very well, suppoase I have a
vector<pair<unsigned int, unsigned int> > vec1 and the contents are

{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>}

what I want is to create another vector, vector<int> vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 ==> 0x00000000,
0x000000FF & 0xFF000000 ==> 0x00000000,
0x10000000 & 0xFF000000 ==> 0x10000000,
0x2FFFFFFF & 0xFF000000 ==> 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

It''s easy to specifically write a for loop, just wonder how to do it
use for_each.



You will have to implement a functor that will do that. Boost library
has some mechanisms that are not available in the standard library yet.
For example, there is no simple functor to extract ''first'' or ''second''
from a pair.

Something like:

struct skim_pairs_to {
vector<int>& collector;
skim_pairs_to(vector<int>& c) : collector(c) {}
void operator()(const std::pair<unsigned,unsigned>& p) {
collector.push_back(p.first & 0xff000000);
collector.push_back(p.second & 0xff000000);
}
};

...
std::for_each(vec1.begin(), vec1.end(), skim_pairs_to(vec2));

should do it. I didn''t test the code.

Victor


John Black <bl***@eed.com> wrote:

Hi,
I am not familiar with for_each very well, suppoase I have a
vector< pair< unsigned int, unsigned int > > vec1 and the contents are

{ < 0x00000000, 0x000000FF >, < 0x10000000, 0x2FFFFFFF > }

what I want is to create another vector, vector< int > vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 == > 0x00000000,
0x000000FF & 0xFF000000 == > 0x00000000,
0x10000000 & 0xFF000000 == > 0x10000000,
0x2FFFFFFF & 0xFF000000 == > 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.
You only put 3 items in vec2, was that on purpose? IE are repeted values
not supposed to be entered?

If that''s the case, I would insert into a set first, then copy from the
set to the vector (see below...)

It''s easy to specifically write a for loop, just wonder how to do it
use for_each.



The same way, except the loop body would be in a functor. So you might
start with:

for ( vector< pair< unsigned, unsigned > >::iterator it = v.begin();
it != v.end(); ++it )
{
v2.push_back( it->first & 0xFF000000 );
v2.push_back( it->second & 0xFF000000 );
}

This would become:

struct filler {
vector< unsigned >& v;
filler( vector< unsigned >& v ): v( v ) { }
void operator()( const pair< unsigned, unsigned >& p ) {
v.push_back( p.first & 0xFF000000 );
v.push_back( p.second & 0xFF000000 );
}
};

and:

for_each( v.begin(), v.end(), filler( v2 ) );

Seems like a bit of a waste. We''ve created a new type, that can only be
used in this one place, and when someone encounters the ''for_each'' he
needs to search the code to find out what this new type does.

What if we could make something more resuable, and at the same time do a
better job of expressing what is happening at the place where it is
supposed to happen?

Let''s take a look at what we are doing. Basically it''s a transform
except each value in the first container is being transformed twice and
placed in the second container. So we can model something off of
std::transform.

template < typename InputIter, typename OutputIter,
typename Op1, typename Op2 >
OutputIter expanding_transform( InputIter first, InputIter last,
OutputIter result, Op1 op1, Op2 op2 )
{
while ( first != last )
{
*result++ = op1( *first );
*result++ = op2( *first );
++first;
}
return result;
}

Maybe the above isn''t all that reusable, but it''s certanly more resuable
than the ''filler'' type above. For example, we can use this function to
output our vector< pair< unsigned, unsigned > > to cout... The fact that
we can already see two uses for this function argues well for its
reusablity.

Now, what arguments do we need to pass into this function? The first two
are easy ''v.begin()'' and ''v.end()'' we see this all the time in the
standard algorithms. The third is a little harder, but still often seen:
''back_inserter( v2 )''. Of course ''v'' is our vector< pair< unsigned,
unsigned > > and ''v2'' is our new vector< unsigned >... For the last two
parameters, we need to do some more work.

First we examine the ''functional'' part of the stl. We find a
''logical_and'' functor, but no ''bit_and''. Oh well, that''s easy to fix:

template < typename T >
struct bit_and : public std::binary_function< T, T, T >
{
T operator()( const T& x, const T& y ) const { return x & y; }
};

So, for each of the Ops in our expanding_transform, we need to call
''bit_and'' were the first argument is the first and second item in the
pair, and the second argument is 0xFF000000. Let''s make a functor that
does that:

binder2nd< bit_and< unsigned > > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );

Let''s make sure we know what high_8_mask does:

assert( high_8_mask( 0x12345678 ) == 0x12000000 );

Unfortunatly, we can''t just pass our pair< unsigned, unsigned > into the
above because it only takes one unsigned value.

Now we have to look in the past. The origional STL had several useful
functors that never made it into the standard. Two of them specifically
dealt with manipulating pair objects so that they could be used in
standard functors: select1st and select2nd. You can find them on SGI''s
website and I''m sure other websites have them. They both do exactly what
you would think. You pass in a pair object, and it returns either the
first or second object of the pair.

Another useful functor is ''unary_compose''; which takes two other
functors and combines them like this: f1( f2( x ) ). There is also a
useful function ''compose1'' that helps build a unary_compose objects (
like the way ''make_pair'' builds ''pair'' objects. ) You can also find this
in boost where it''s called ''compose_f_gx''...

With these three functors in our arsenal we can build the functors that
will be used by our new algorithm.

I also want to make the pair easer to work with so I''ll make a typedef.

Now I''ll put all of this together to show how it works:

typedef pair< unsigned, unsigned > two_flags;

binder2nd< bit_and< unsigned > > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );

expanding_transform( v.begin(), v.end(), back_inserter( v2 ),
compose1( high_8_mask, select1st< two_flags >() ),
compose1( high_8_mask, select2nd< two_flags >() ) );

There you go, we have written the loop using lots of small, highly
reusable components.

Now back to my question above about no repeat values. If that''s the case
then insert into a set:

set< unsigned > s;
binder2nd< bit_and<unsigned int> > high_8_mask =
bind2nd( bit_and< unsigned >(), 0xFF000000 );
expanding_transform( v.begin(), v.end(),
inserter( s, s.begin() ),
compose1( high_8_mask, select1st< two_flags >() ),
compose1( high_8_mask, select2nd< two_flags >() ) );
copy( s.begin(), s.end(), back_inserter( v2 ) );


John Black <bl***@eed.com> wrote in message news:<40***************@eed.com>...

Hi,
I am not familiar with for_each very well, suppoase I have a
vector<pair<unsigned int, unsigned int> > vec1 and the contents are

{<0x00000000, 0x000000FF>, <0x10000000, 0x2FFFFFFF>}

what I want is to create another vector, vector<int> vec2, which store
all the first 8 bit heads of the integer in vec1, for the above example,

0x00000000 & 0xFF000000 ==> 0x00000000,
0x000000FF & 0xFF000000 ==> 0x00000000,
0x10000000 & 0xFF000000 ==> 0x10000000,
0x2FFFFFFF & 0xFF000000 ==> 0x2F000000,

then vec2 should be {0x00000000, 0x10000000, 0x2F000000}.

It''s easy to specifically write a for loop, just wonder how to do it
use for_each.



IMO, you''re getting the steps out of order. First you need to pick
the right algorithm, THEN you need to figure out how to use it.

In this case, std::transform is MUCH better suited to the job (at
least IMO).

// warning: this code is incomplete and therefore untested.

// save a little typing:
typedef std::pair<unsigned int, unsigned int> dt;

// define what we''re going to do to each item:
struct top8 {
unsigned int operator()(dt const &d) {
// assumes 32-bit ints.
return d.first & 0xff000000;
}
};

// define vectors for input and output:
std::vector<dt> vec1;
std::vector<unsigned int> vec2;

// code to fill vec1 goes here.

// transform the input into the output:
std::transform(vec1.begin(), vec1.end(), std::back_inserter(vec2),
top8);

Arrogant prediction: nobody will post a better solution using
for_each. :-)

P.S. Of course, I get to define "better". <G>

--
Later,
Jerry.

The universe is a figment of its own imagination.


这篇关于如何使用for_each从向量中收集一些信息到另一个向量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆