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