Vlad
Vlad

Reputation: 256

Group every n-th element of array

I have an array:

array = [1, 2, 3, 4, 5, 6, 7, 8, 9]

How do I group every n-elements of array? For example, for 3:

[[1, 4, 7], [2, 5, 8], [3, 6, 9]]

I wrote this code, but it's ugly:

array.each_with_index.group_by { |e, i| i % 3}.map {|h| h[1].map { |e| e[0] }}

Upvotes: 3

Views: 2899

Answers (4)

Cary Swoveland
Cary Swoveland

Reputation: 110755

This could also be done by creating a hash, then extracting the values. For Ruby 1.9+, this would preserve the order of the elements of the array.

Code

def bunch(arr,ngroups)
  arr.each_with_index.with_object(Hash.new { |h,k| h[k]=[] }) { |(e,i),h|
       h[i%ngroups] << e }
     .values
end

Example

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]

bunch(arr,1) #=> [[1, 2, 3, 4, 5, 6, 7, 8, 9]] 
bunch(arr,2) #=> [[1, 3, 5, 7, 9], [2, 4, 6, 8]] 
bunch(arr,3) #=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 
bunch(arr,4) #=> [[1, 5, 9], [2, 6], [3, 7], [4, 8]] 
bunch(arr,5) #=> [[1, 6], [2, 7], [3, 8], [4, 9], [5]] 
bunch(arr,6) #=> [[1, 7], [2, 8], [3, 9], [4], [5], [6]] 
bunch(arr,7) #=> [[1, 8], [2, 9], [3], [4], [5], [6], [7]] 
bunch(arr,8) #=> [[1, 9], [2], [3], [4], [5], [6], [7], [8]] 
bunch(arr,9) #=> [[1], [2], [3], [4], [5], [6], [7], [8], [9]] 

Alternatives

If the argument were instead the size of each group, grp_size, we could compute:

ngroups = (arr.size+grp_size-1)/grp_size

The operative line of the method could instead be written:

arr.each_with_index.with_object({}) { |(e,i),h| (h[i%ngroups] ||= []) << e }
   .values

Upvotes: 0

Nick Veys
Nick Veys

Reputation: 23949

Here's an easy way:

array.each_slice(3).to_a.transpose
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]] 

Upvotes: 9

sawa
sawa

Reputation: 168249

Nick Veys' answer is most straightforward, but here is another way.

array.group_by.with_index{|_, i| i % 3}.values
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Upvotes: 5

m0bi5
m0bi5

Reputation: 9475

Try this way out:

irb(main):002:0> a =  Array(1..9)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
irb(main):004:0> a.each_slice(3).to_a.transpose # good
=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Not what you want? Let me know

Upvotes: 0

Related Questions