我正试着把一个数组分成三组。我希望在开头有剩余的部分(在下面的示例中[1, 2])。

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
...
#=> [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

有什么好方法可以做到这一点吗?
分割数组的通常方法是:
arr.each_slice(3)
# => [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11]]

这将在最后给出剩余的[10, 11]。我试着如下,认为each_slice可能会接受一个否定的参数,并将其读作向后遍历数组。
arr.each_slice(-3)

唉,没用。

最佳答案

尽管可以将数组反转三次,但有一种更有效的方法可以实现目标:

arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
a = arr.dup # not to modify it inplace
[a.shift(a.size % 3)] + a.each_slice(3).to_a
#⇒ [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

顺便说一句,arr.each_slice(3)返回的是枚举数,而不是您在问题中发布的数组。
按照Cary Swoveland的建议,UPD或作废:
n = a.size % 3
[a[0...n]] + a[n..-1].each_slice(3).to_a

upd通过@sawa清除dup
[a.first(a.size % 3)] + a.drop(a.size % 3).each_slice(3).to_a

upd只是出于好奇(假设输入没有dup元素):
([nil] * (3 - a.size % 3) + a).each_slice(3).to_a.tap do |a|
  a.unshift(a.shift.compact!)
end

上面的代码可能安全地运行在原始数组上,它不会就地修改它。
upd2正如stefan在评论中指出的,如果数组可以被3整除,那么上面的任何一个都将产生一个初始空切片。所以,正确的解决方案(最快的,顺便说一句)应该是:
(arr.size % 3).zero? ? arr.each_slice(3).to_a : ANY_OF_THE_ABOVE

10-04 19:40