`Array#each_slice`,在开头留下余数

时间:2016-01-05 07:41:05

标签: arrays ruby multidimensional-array

我正在尝试将数组切成三组。我希望将余数放在开头(以下示例中为[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)
唉,它没用。

2 个答案:

答案 0 :(得分:10)

虽然有人可能会将数组反转三次,但实现目标的方法更为有效:

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]]

BTW,arr.each_slice(3)返回一个枚举器,而不是你在问题中发布的数组。

更新或者,正如Cary Swoveland所建议的那样,dup无效:

n = a.size % 3
[a[0...n]] + a[n..-1].each_slice(3).to_a

更新通过@sawa删除dup

[a.first(a.size % 3)] + a.drop(a.size % 3).each_slice(3).to_a

upd 只是出于好奇(假设输入没有nil元素):

([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

答案 1 :(得分:7)

reverseeach_slice的简单组合可以解决问题:

arr.reverse.each_slice(3).map(&:reverse).reverse
#=> [[1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]

<强>解释

我正在反转数组并执行each_slice。这会给我:

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

现在我正在迭代这个并且反转每个子数组以使预期的子数组序列与.map(&:reverse)匹配。最后,我正在反转整个数组以获得所需的序列(最后.reverse)。