Grouping by twos

Another of those trivial little problems that I obsess about finding
the Proper way to do - what’s a nice, idiomatic Ruby way to go from
[a,b,c,d…] to [[a,b],[c,d],[e,f],…]? Note that I want to
preserve the ordering, so to_hash won’t work.

One way I thought of was
b = []
while a[0] do
b << [a.shift, a.shift]
end

which works but doesn’t look particularly elegant.

martin

martindemello@yahoo.com (Martin DeMello) writes:

Another of those trivial little problems that I obsess about finding
the Proper way to do - what’s a nice, idiomatic Ruby way to go from
[a,b,c,d…] to [[a,b],[c,d],[e,f],…]? Note that I want to
preserve the ordering, so to_hash won’t work.

One way I thought of was
b =
while a[0] do
b << [a.shift, a.shift]
end

This isn’t much better, but

 b = []
 b << a.slice!(0,2) until a.empty?

Cheers

Dave

I ran into the same requirement and I solved it by extending the Array
class. Have a look…

class Array

···

#---------------------------------------------------------------------
# each_group
#---------------------------------------------------------------------
def each_group ( sizeof )
limitOf = length-1
0.step( limitOf, sizeof ) { |i| yield( self[i,sizeof] ) }
end

#---------------------------------------------------------------------
# collect_each_group
#---------------------------------------------------------------------
def collect_each_group ( sizeof )
	rtn = []
	limitOf = length-1
	0.step( limitOf, sizeof ) { |i| rtn << yield( self[i,sizeof] ) }
	rtn
end

end

a = [ 1,2,3,4,5,6,7,8,9,10 ]
b = a.collect_each_group(2) { |items| items }
and b = [[1,2],[3,4],[5,6],[7,8],[9,10]]

Hope it helps…

-----Original Message-----
From: Martin DeMello [mailto:martindemello@yahoo.com]
Sent: October 20, 2002 19:52
To: ruby-talk ML
Subject: Grouping by twos

Another of those trivial little problems that I obsess about finding
the Proper way to do - what’s a nice, idiomatic Ruby way to go from
[a,b,c,d…] to [[a,b],[c,d],[e,f],…]? Note that I want to
preserve the ordering, so to_hash won’t work.

One way I thought of was
b = []
while a[0] do
b << [a.shift, a.shift]
end

which works but doesn’t look particularly elegant.

martin

“Allen Mitchell” ajm@nb.sympatico.ca wrote in message news:MHEFIIKIPJCFBKBGMHOGEEPPCOAA.ajm@nb.sympatico.ca

I ran into the same requirement and I solved it by extending the Array
class. Have a look…

Neat. Getting positively verbose, but here’s an extension to Enumerable

module Enumerable
def eachn(n)
a =
if block_given?
each {|i|
a << i
if a.length == n
yield a
a =
end
}
yield a unless a.empty? #possibly padded with nils
else
b =
eachn(n) {|i| b << i}
b
end
end
end

a = (1…10).to_a
b = a.eachn(2)
puts a.inspect, # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
b.inspect # => [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]

But the method name is short and expressive. I like that. :slight_smile:

Hm, from `eachn’ I’d expect:

a.eachn(2) do |x, y|

end

a.eachn(3) do |x, y, z|

end

I’d rewrite `b = a.eachn(2)’ in:

b = a.collectn(2) {|a, b| [a, b]}

For which an optional blockless form would make sense:

b = a.collectn(2)

Massimiliano

···

On Tue, Oct 22, 2002 at 05:34:47AM +0900, Martin DeMello wrote:

Neat. Getting positively verbose,