Iterating over an array n element at a time

K

Kim Pedersen

Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim
 
A

ara.t.howard

Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

harp:~ > ruby -r enumerator -e' %w( 1 2 3 4 5 ).each_slice(2){|slice| p slice} '
["1", "2"]
["3", "4"]
["5"]


harp:~ > ruby -r enumerator -e' %w( 1 2 3 4 5 ).each_cons(2){|slice| p slice} '
["1", "2"]
["2", "3"]
["3", "4"]
["4", "5"]


-a
 
T

Trans

Kim said:
Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

enumerator is probably better since it is built-in, but...

require 'facet/enumerable/each_by'
a = [1,1,1,2,2,2,3,3,3]
a.each_by(3) { |x,y,z| print x,y,z,"\n" }
111
222
333

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

T.
 
L

Logan Capaldo

Kim said:
Is there an elegant way to iterate over an array n elements at a
time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

enumerator is probably better since it is built-in, but...

require 'facet/enumerable/each_by'
a = [1,1,1,2,2,2,3,3,3]
a.each_by(3) { |x,y,z| print x,y,z,"\n" }
111
222
333

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.
( ) already have meaning in block arguments though
e.g.:

{ :a => 1, :b => 2 }.inject({}) { |h, (k, v)| h[k] = v + 1; h }
#=> {:b=>3, :a=>2}
 
M

M. Edward (Ed) Borasky

Trans said:
Kim said:
Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

enumerator is probably better since it is built-in, but...

require 'facet/enumerable/each_by'
a = [1,1,1,2,2,2,3,3,3]
a.each_by(3) { |x,y,z| print x,y,z,"\n" }
111
222
333

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

T.
I think I'd recast the array as a matrix and then iterate over rows (or
columns, depending on which way you did the recast).
 
T

Trans

Logan said:
( ) already have meaning in block arguments though
e.g.:

{ :a => 1, :b => 2 }.inject({}) { |h, (k, v)| h[k] = v + 1; h }
#=> {:b=>3, :a=>2}

Right, but it seems to be similar in nature. Could it not be used for
both?

Otherwise another notation

{ |[x,y,z]| ... }

perhaps.

T.
 
M

Martin DeMello

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

require 'enumerator'

module Enumerable
def eachn(&block)
n = block.arity
each_slice(n) {|i| block.call(*i)}
end
end

a = (1..10).to_a
a.eachn {|x,y,z| p [x,y,z]}

martin
 
R

Rick DeNatale

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

require 'enumerator'

module Enumerable
def eachn(&block)
n = block.arity
each_slice(n) {|i| block.call(*i)}
end
end

a = (1..10).to_a
a.eachn {|x,y,z| p [x,y,z]}

Nice! As it turns out that *i in the block.call invocation isn't
needed. The proc call method does the right thing in this case.

Also there's no need to turn the range into an array, it'll work
directly since ranges mixin Enumerable
 
R

Robert Klemme

Trans said:
Kim said:
Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

enumerator is probably better since it is built-in, but...

require 'facet/enumerable/each_by'
a = [1,1,1,2,2,2,3,3,3]
a.each_by(3) { |x,y,z| print x,y,z,"\n" }
111
222
333

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

T.
Note though that your code does something different than each_cons which
moves a sliding window while your code iterates in chunks! See:

robert@fussel ~
$ ruby -r enumerator -e' %w( 1 2 3 4 5 ).each_cons(2){|a, b| p a, b,
"-"} '
"1"
"2"
"-"
"2"
"3"
"-"
"3"
"4"
"-"
"4"
"5"
"-"

robert@fussel ~
$

Kind regards

robert
 
T

Trans

Robert said:
Trans said:
Kim said:
Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

enumerator is probably better since it is built-in, but...

require 'facet/enumerable/each_by'
a = [1,1,1,2,2,2,3,3,3]
a.each_by(3) { |x,y,z| print x,y,z,"\n" }
111
222
333

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

T.
Note though that your code does something different than each_cons which
moves a sliding window while your code iterates in chunks! See:

Right. But wasn't that what was originally asked for? In any case, I
am only meaning the "chunk" case with my example, but certainly one
could conceive of a notion to "slide" too. The advantage of notation
over more methods is that it works with derivatives. Eg. pseudo code:

[1,1,2,2,3,4].select { |slide(a,b)| a == b }

Otherwise you need a select_slice, select_cons, collect_slice,
collect_cons, and so on.

T.
 
N

nobu

Hi,

At Sun, 6 Aug 2006 19:55:37 +0900,
Trans wrote in [ruby-talk:206591]:
[1,1,2,2,3,4].select { |slide(a,b)| a == b }

Otherwise you need a select_slice, select_cons, collect_slice,
collect_cons, and so on.

Longer a little, but it's possible with enumerator.

[1,1,2,2,3,4].enum_cons(2).select {|a, b| a == b}
 
R

Rick DeNatale

Robert said:
Trans said:
Kim Pedersen wrote:
Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333

//kim

enumerator is probably better since it is built-in, but...

require 'facet/enumerable/each_by'
a = [1,1,1,2,2,2,3,3,3]
a.each_by(3) { |x,y,z| print x,y,z,"\n" }
111
222
333

But why not have Ruby fill those arguments out automatically? This
already does:

a = [[1,1,1],[2,2,2],[3,3,3]]
a.each { |x,y,z| print x,y,z,"\n" }

So couldn't some "slurping" indicator be used?

a = [1,1,1,2,2,2,3,3,3]
a.each { |(x,y,z)| print x,y,z,"\n" }

Or something.

T.
Note though that your code does something different than each_cons which
moves a sliding window while your code iterates in chunks! See:

Right. But wasn't that what was originally asked for? In any case, I
am only meaning the "chunk" case with my example, but certainly one
could conceive of a notion to "slide" too. The advantage of notation
over more methods is that it works with derivatives. Eg. pseudo code:

[1,1,2,2,3,4].select { |slide(a,b)| a == b }

Otherwise you need a select_slice, select_cons, collect_slice,
collect_cons, and so on.

T.

I might be wrong, but I can't see how these parameter markers can be
implemented without a lot of changes.

The syntax of block literals needs to be changed to allow the markers,
then the Proc class needs to be changes so that the methods like
select can see the markers, then all the methods in Enumerable (and
anywhere else they are reimplemented e.g. Hash), need to be changed to
be sensitive to them, and make them "slurpable."

It seems like these "slurp indicators" are trying to move the loop
control out of the internal iterators, and to make the block look a
teeny bit like a java style iterator in some strange sense, which
makes the idea seem a little less ruby-like.

Martin DeMello's eachn method is a neat trick which makes use of
existing mechanisms. but I suspect that making such stuff general
isn't such a good idea for Ruby, maybe for a forked language (sluby?)
for those who like such stuff.

For Ruby, I think that Nakada-san's suggestion is a better way to
compose such functionality.
--
Rick DeNatale

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/
 
M

Marcelo Alvim

Hi,

Sorry about the real newbie interrupting the high level thread, but...

I liked very much the "eachn" method from Martin, and decided to test
it out. I got a "Undefined method 'each_slice'" for the array. Went to
ruby-doc.org, and the core docs have each_slice defined in module
Enumerable. I have Ruby 1.8.4 installed. Does anyone know why is that
not working for me?

Thanks,
Marcelo Alvim.
Kim said:
Is there an elegant way to iterate over an array n elements at a time?
e.g. something like...

a = [1,1,1,2,2,2,3,3,3]

a.each(3) do |x,y,z|
print x,y,z,"\n"
end

prints...
111
222
333
 
M

Martin DeMello

Hi,

Sorry about the real newbie interrupting the high level thread, but...

I liked very much the "eachn" method from Martin, and decided to test
it out. I got a "Undefined method 'each_slice'" for the array. Went to
ruby-doc.org, and the core docs have each_slice defined in module
Enumerable. I have Ruby 1.8.4 installed. Does anyone know why is that
not working for me?


You need to require 'enumerator', which adds additional methods like
each_slice to Enumerable.

martin
 
M

Martin DeMello

require 'enumerator'

module Enumerable
def eachn(&block)
n = block.arity
each_slice(n) {|i| block.call(*i)}
end
end

a = (1..10).to_a
a.eachn {|x,y,z| p [x,y,z]}

Nice! As it turns out that *i in the block.call invocation isn't
needed. The proc call method does the right thing in this case.

Huh - you're right, block.call(i) works nicely without the splat. I
guess it's because the argument list 'picks apart' the array. Good
catch.

martin
 
M

Marcelo Alvim

Just a tiny little trap you fell into, look at this
[1,2,3].each_slice(2){|s| p s}
NoMethodError: undefined method `each_slice' for [1, 2, 3]:Array
from (irb):1

but

irb(main):003:0> require 'enumerator'
=> true
irb(main):004:0> [1,2,3].each_slice(2){|s| p s}
[1, 2]
[3]

I have fallen into that one more than once and I still will, it is a little
bit unclear why Enumerable is not in the core while it is in the core doc.
But well just a minor hickup.

Oh, I see! Thanks for the pointer.

I thought Array mixed that in, so it should be defined for it. But
then again, I'm still getting used to modules, mixins and such. Been
too long in a Java-only world...

Thanks again,
Marcelo Alvim.
 
M

Martin DeMello

Just a tiny little trap you fell into, look at this
[1,2,3].each_slice(2){|s| p s}
NoMethodError: undefined method `each_slice' for [1, 2, 3]:Array
from (irb):1

but

irb(main):003:0> require 'enumerator'
=> true
irb(main):004:0> [1,2,3].each_slice(2){|s| p s}
[1, 2]
[3]

I have fallen into that one more than once and I still will, it is a little
bit unclear why Enumerable is not in the core while it is in the core doc.
But well just a minor hickup.

Oh, I see! Thanks for the pointer.

I thought Array mixed that in, so it should be defined for it. But
then again, I'm still getting used to modules, mixins and such. Been
too long in a Java-only world...

Array does mix Enumerable in. However, the core Enumerable module
doesn't include each_slice; that is provided by the 'enumerator'
library, which reopens Enumerable and adds some methods to it. Note
that enumerator is in the standard lib rather than in the core.

http://www.ruby-doc.org/stdlib/libdoc/enumerator/rdoc/index.html

martin
 

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,565
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top