Splitting a Ruby Array in equal parts


I'm working on a personal project that involves calendars. One of the features I wanted was to be able to print a calendar like this:

  | Mon | Tue | Wed | Thu | Fri | Sat | Sun |
  |-----+-----+-----+-----+-----+-----+-----|
  |   1 |   2 |   3 |   4 |   5 |   6 |   7 |
  |   8 |   9 |  10 |  11 |  12 |  13 |  14 |
  |  15 |  16 |  17 |  18 |  19 |  20 |  21 |
  |  22 |  23 |  24 |  25 |  26 |  27 |  28 |

For that I needed to split a 28-ish Array into 4 or 5 rows (weeks). In order to make this happen I took the long way around:

  (1..28).group_by { |n| (n-1) / 7}.values
  # => [[1, 2, 3, 4, 5, 6, 7],
  #     [8, 9, 10, 11, 12, 13, 14],
  #     [15, 16, 17, 18, 19, 20, 21],
  #     [22, 23, 24, 25, 26, 27, 28]]

This works, but it's extremely ugly. So I went digging into the Array and Enumerable documentation and found the each_slice method in the second one. It accepts the expected number of elements per sub-array and returns an Enumerator. Converting it to an Array gives us the result we expected

  weeks = (1..28).each_slice(7)

  weeks
  # => #<Enumerator: ...>

  weeks.to_a
  # => [[1, 2, 3, 4, 5, 6, 7],
  #     [8, 9, 10, 11, 12, 13, 14],
  #     [15, 16, 17, 18, 19, 20, 21],
  #     [22, 23, 24, 25, 26, 27, 28]]

If the number of elements isn't an exact multiple of the expected number of elements, the last sub-array becomes smaller than the rest.

  weeks = (1..31).each_slice(7).to_a
  # => [[1, 2, 3, 4, 5, 6, 7],
  #     [8, 9, 10, 11, 12, 13, 14],
  #     [15, 16, 17, 18, 19, 20, 21],
  #     [22, 23, 24, 25, 26, 27, 28],
  #     [29, 30, 31]]

By passing it a block, each_slice will iterate through each sub-array

  (1..8).each_slice(3) do |arr|
    arr.each do |n|
      print "(#{n})"
    end
    print "\n"
  end

  # >> (1)(2)(3)
  # >> (4)(5)(6)
  # >> (7)(8)

Thanks for reading.

Saluti.