Running multiple closures per iteration

J

Joshua Chia

Is there a way to run more than one closure per iteration through a
collection? For example, if I want to do the following two things, can
I combine them so that I only end up with one pass over the collection,
without doing a manual for loop?

o = a.select {|x| x >= 0}
p = a.inject(0) {|s, x| s += x}

Such a combination is useful when iterating through a collection is
expensive, e.g. on a large file on a slow disk.
 
J

Joel VanderWerf

Joshua said:
Is there a way to run more than one closure per iteration through a
collection? For example, if I want to do the following two things, can
I combine them so that I only end up with one pass over the collection,
without doing a manual for loop?

o = a.select {|x| x >= 0}
p = a.inject(0) {|s, x| s += x}

Such a combination is useful when iterating through a collection is
expensive, e.g. on a large file on a slow disk.


Did you mean

o = a.select {|x| x >= 0}
p = o.inject(0) {|s, x| s += x}
^^^
?

Then you can do this:

a = [1,-1,2,-2,3,-3]
sp = a.inject(0) {|s, x| x >= 0 ? s + x : s}
p sp # ==> 6

(note that += is not needed, + is good enough)

But there is no way in general to combine two iterations.
 
T

Tim Pease

No, I meant to compute two different things from a.

Well, it's not pretty, but here's my best shot at it

o, p = a.inject( [[], 0] ) do |ary,x|
ary[0] << x if x >= 0
ary[1] += x
ary
end

I don't think Ruby natively supports such a creature, though. Please
correct me if I'm wrong.

Blessings,
TwP
 
S

Stefano Cobianchi

Is there a way to run more than one closure per iteration through a
collection? For example, if I want to do the following two things, can
I combine them so that I only end up with one pass over the collection,
without doing a manual for loop?

o = a.select {|x| x >= 0}
p = a.inject(0) {|s, x| s += x}

btw, you don't need the += operator here:
a.inject(0) {|s, x| s + x}
=> 6
Such a combination is useful when iterating through a collection is
expensive, e.g. on a large file on a slow disk.

o = 0; p = []
a.each { |x| o << x if x >= 0; p += x }
 
D

dblack

Hi --

Is there a way to run more than one closure per iteration through a
collection? For example, if I want to do the following two things, can
I combine them so that I only end up with one pass over the collection,
without doing a manual for loop?

o = a.select {|x| x >= 0}
p = a.inject(0) {|s, x| s += x}

btw, you don't need the += operator here:
a.inject(0) {|s, x| s + x}
=> 6
Such a combination is useful when iterating through a collection is
expensive, e.g. on a large file on a slow disk.

o = 0; p = []
a.each { |x| o << x if x >= 0; p += x }
a.each { |x| p << x if x >= 0; o += x }

:)


David

--
* Books:
RAILS ROUTING (new! http://www.awprofessional.com/title/0321509242)
RUBY FOR RAILS (http://www.manning.com/black)
* Ruby/Rails training
& consulting: Ruby Power and Light, LLC (http://www.rubypal.com)
 
S

Simon Kröger

Tim said:
No, I meant to compute two different things from a.

Well, it's not pretty, but here's my best shot at it

o, p = a.inject( [[], 0] ) do |ary,x|
ary[0] << x if x >= 0
ary[1] += x
ary
end

you can beautify this to

o, p = a.inject( [[], 0] ) do |(l, s), x|
[x >= 0 ? l << x : l, s + x]
end
I don't think Ruby natively supports such a creature, though. Please
correct me if I'm wrong.

Well, depends on what 'natively' realy means...
Blessings,
TwP

cheers

Simon
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top