iteration the ruby way

  • Thread starter Navindra Umanee
  • Start date
N

Navindra Umanee

Hi,

I have a question about The Ruby Way. Pickaxe gives the following
example for using iterators in Ruby:

a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }

This outputs:

a -- b -- c --

But what if I want to print "a -- b -- c"? What's the proper Ruby way
of doing that? Is there some way of detecting the last element? I
mean, obviously I can do it with a for/while loop or something...

Thanks,
Navin.
 
J

John Wilger

Hi,

I have a question about The Ruby Way. Pickaxe gives the following
example for using iterators in Ruby:

a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }

This outputs:

a -- b -- c --

But what if I want to print "a -- b -- c"? What's the proper Ruby way
of doing that?

a = ["a","b","c"]
puts a.join(' - ')

--
Regards,
John Wilger

-----------
Alice came to a fork in the road. "Which road do I take?" she asked.
"Where do you want to go?" responded the Cheshire cat.
"I don't know," Alice answered.
"Then," said the cat, "it doesn't matter."
- Lewis Carrol, Alice in Wonderland
 
S

sera

Use join:

a = [ "a", "b", "c" ]
puts a.join( " -- " )

And while we're at it, you can use the %w( ... ) construct to quickly
make an array of strings:

puts %w( a b c ).join( " -- " )
 
J

Joe Van Dyk

Hi,

I have a question about The Ruby Way. Pickaxe gives the following
example for using iterators in Ruby:

a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }

This outputs:

a -- b -- c --

But what if I want to print "a -- b -- c"? What's the proper Ruby way
of doing that? Is there some way of detecting the last element? I
mean, obviously I can do it with a for/while loop or something...

Thanks,
Navin.

This probably isn't what you're looking for... but:

puts a.join(" -- ")
 
N

Navindra Umanee

John Wilger said:
I have a question about The Ruby Way. Pickaxe gives the following
example for using iterators in Ruby:

a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }

This outputs:

a -- b -- c --

But what if I want to print "a -- b -- c"? What's the proper Ruby way
of doing that?

a = ["a","b","c"]
puts a.join(' - ')

I guess I over-simplified. I really want to do computations based on
each element and compute my output. However, it's slightly different
for the last element. I would like to detect the last element in the
iteration.

For example:

bottom_items.each{ |item|
do_something_with(item[0], item[1], item[2])
if_not_last_item_do_this
}

Thanks,
Navin.
 
D

David A. Black

Hi --

John Wilger said:
I have a question about The Ruby Way. Pickaxe gives the following
example for using iterators in Ruby:

a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }

This outputs:

a -- b -- c --

But what if I want to print "a -- b -- c"? What's the proper Ruby way
of doing that?

a = ["a","b","c"]
puts a.join(' - ')

I guess I over-simplified. I really want to do computations based on
each element and compute my output. However, it's slightly different
for the last element. I would like to detect the last element in the
iteration.

For example:

bottom_items.each{ |item|
do_something_with(item[0], item[1], item[2])
if_not_last_item_do_this
}

If your enumerable object has a size method, you can do:

bottom_items.each_with_index do |item,i|
do_something_with(...)
unless i == bottom_items.size - 1
...
end
end

or something similar with #each_index.


David
 
S

sera

I'd probably use Enumerable#each_with_index.

ary = [ 1, 2, 3, 4 ]
ary.each_with_index { |elt, i|
if i < ary.size - 1
puts elt
else
puts elt * 10
end
}

which will output:

1
2
3
40
 
M

Martin DeMello

David A. Black said:
If your enumerable object has a size method, you can do:

bottom_items.each_with_index do |item,i|
do_something_with(...)
unless i == bottom_items.size - 1
...
end
end

or something similar with #each_index.

And if it doesn't, this approach should work:

irb(main):005:0> b = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):006:0> b.inject(lambda {}) {|a,v| a.call; puts v; a = lambda { puts "-
--" }}

martin

p.s. who'd have thunk it
 
E

Eric Hodel

--Apple-Mail-48-402084306
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII; format=flowed

John Wilger said:
I have a question about The Ruby Way. Pickaxe gives the following
example for using iterators in Ruby:

a = [ "a", "b", "c" ]
a.each {|x| print x, " -- " }

This outputs:

a -- b -- c --

But what if I want to print "a -- b -- c"? What's the proper Ruby
way
of doing that?

a = ["a","b","c"]
puts a.join(' - ')

I guess I over-simplified. I really want to do computations based on
each element and compute my output. However, it's slightly different
for the last element. I would like to detect the last element in the
iteration.

For example:

bottom_items.each{ |item|
do_something_with(item[0], item[1], item[2])
if_not_last_item_do_this
}

items = items.map do |item|
do_something_with item
end

puts items.join(' -- ')


--
Eric Hodel - (e-mail address removed) - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

--Apple-Mail-48-402084306
content-type: application/pgp-signature; x-mac-type=70674453;
name=PGP.sig
content-description: This is a digitally signed message part
content-disposition: inline; filename=PGP.sig
content-transfer-encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (Darwin)

iD8DBQFCA/+fMypVHHlsnwQRAu+xAJwIRqHdvUzGOyZ//DtJLmEDbQ53uACgvQuP
nbNiSOMoVetEzGql2WIIji4=
=zd2M
-----END PGP SIGNATURE-----

--Apple-Mail-48-402084306--
 
R

Robert Klemme

Martin DeMello said:
David A. Black said:
If your enumerable object has a size method, you can do:

bottom_items.each_with_index do |item,i|
do_something_with(...)
unless i == bottom_items.size - 1
...
end
end

or something similar with #each_index.

And if it doesn't, this approach should work:

irb(main):005:0> b = [1,2,3,4,5]
=> [1, 2, 3, 4, 5]
irb(main):006:0> b.inject(lambda {}) {|a,v| a.call; puts v; a = lambda {
puts "-
--" }}

martin

p.s. who'd have thunk it

Interesting idea to use a proc. I never thought of that. Btw, you don't
need the assignment to "a".
1 -- 2 -- 3 -- 4 -- 5=> #<Proc:0x100c43a0@(irb):12>


Um... Here's another one - without lambdas:
b = [1,2,3,4,5] => [1, 2, 3, 4, 5]
print b.inject{|x,y| print x, " -- ";y}, "\n"
1 -- 2 -- 3 -- 4 -- 5
=> nil1 -- 2 -- 3 -- 4 -- 5
=> nil

If you really need two different manipulation functions for the first n-1
elements and the last element you can do:

puts transform_last( b.inject{|x,y| print transform_first_n(x), " -- ";y} )

There's a nice speciality about inject with no arguments: on the first call
the two block args are set to the first and second iteration elements...

:)

Kind regards

robert
 
M

Martin DeMello

Robert Klemme said:
1 -- 2 -- 3 -- 4 -- 5

Ah, nice. I always forget you can use inject both for the side effect
and for the return value simultaneously - I usually use it as an
either/or thing.

martin
 
N

Navindra Umanee

Robert Klemme said:
1 -- 2 -- 3 -- 4 -- 5

Wow. It took me several minutes to understand this stuff, but now
that I do, I really like it!

Thanks again.

Cheers,
Navin.
 
N

Navindra Umanee

Martin DeMello said:
irb(main):006:0> b.inject(lambda {}) {|a,v| a.call; puts v; a = lambda { puts "-
--" }}

Actually, I prefer yours over Robert's because his leaves the last
element dangling (could be useful of course). However, I don't think
the lambda is at all necessary in your case, although I'm sure it
could come in handy in an other situation.

You could simply do:

b.inject("") {|a,v| print a, v; " -- "}

Or if you just want to compute the string instead of just printing:

b.inject {|x,y| "#{x} -- #{y}" }

Although that last doesn't work for what I want to do since I might
have to repeat complex code for both the first element of the
iteration and for y. There's a fix for this:

b.inject(nil) {|x,y| x ? x += " -- " : x = ""; x += "#{y}" }

So now the complex code only has to be written for y.

I love this. It's totally crazy!

Cheers,
Navin.
 
M

Martin DeMello

Navindra Umanee said:
Actually, I prefer yours over Robert's because his leaves the last
element dangling (could be useful of course). However, I don't think
the lambda is at all necessary in your case, although I'm sure it
could come in handy in an other situation.

True, the lambda was overcomplicating it. Robert's version does work
better, though - the thing to note is that the last element is returned
by the inject method, so you can treat it as you like.

martin
 
N

Navindra Umanee

Martin DeMello said:
True, the lambda was overcomplicating it. Robert's version does work
better, though - the thing to note is that the last element is returned
by the inject method, so you can treat it as you like.

In my case that means having to repeat code, which I don't want to do,
but I can see Robert's being useful in a different situation.

I really like the accumulator solution. The one I ended up with is a
slight modification of the last one I posted:

b.inject("") { |a, item|
a += " | " if not a.empty?
a += "#{item}"
}

except with more complex processing on item. I guess this is less
efficient than a direct NilClass test, but I like the way it looks
better. I think it's also easy to understand now and one of the
shorter solutions.

Thanks a lot for yours and everyone else's help on this thread. I
would never have thought of this solution.

Cheers,
Navin.
 
E

Eric Hodel

--Apple-Mail-52-472939997
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset=US-ASCII; format=flowed

In my case that means having to repeat code, which I don't want to do,
but I can see Robert's being useful in a different situation.

I really like the accumulator solution. The one I ended up with is a
slight modification of the last one I posted:

b.inject("") { |a, item|
a += " | " if not a.empty?
a += "#{item}"
}

except with more complex processing on item. I guess this is less
efficient than a direct NilClass test, but I like the way it looks
better. I think it's also easy to understand now and one of the
shorter solutions.

b.map { |a| do_stuff_with a }.join ' | '

Is more clear (and faster!) than the inject way.

--
Eric Hodel - (e-mail address removed) - http://segment7.net
FEC2 57F1 D465 EB15 5D6E 7C11 332A 551C 796C 9F04

--Apple-Mail-52-472939997
content-type: application/pgp-signature; x-mac-type=70674453;
name=PGP.sig
content-description: This is a digitally signed message part
content-disposition: inline; filename=PGP.sig
content-transfer-encoding: 7bit

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (Darwin)

iD8DBQFCBRRnMypVHHlsnwQRAhDUAJ9dR1tBi/VTmMEZLlxAMFOCqDHoNwCfRULH
Zh2/CgNX2xdsr1+WTbhVA+k=
=Zs/b
-----END PGP SIGNATURE-----

--Apple-Mail-52-472939997--
 

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

Forum statistics

Threads
474,166
Messages
2,570,907
Members
47,448
Latest member
DeanaQ4445

Latest Threads

Top