将一个红宝石数组的元素分割成精确数量(几乎)相等大小的子数组

我需要一种方法将一个数组分割成大小大致相等的精确数量的较小数组。有人知道怎么做吗?

比如说

a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
groups = a.method_i_need(3)
groups.inspect
=> [[1,2,3,4,5], [6,7,8,9], [10,11,12,13]]

请注意,这是一个完全独立于 将数组分成块的问题,因为 a.each_slice(3).to_a将产生5个组(而不是3个,像我们希望的那样) ,最终的组可能是一个完全不同于其他组的大小:

[[1,2,3], [4,5,6], [7,8,9], [10,11,12], [13]]  # this is NOT desired here.

在这个问题中,预先指定了所需的块数,每个块的大小最多相差1。

65202 次浏览

你在找 Enumerable#each_slice

a = [0, 1, 2, 3, 4, 5, 6, 7]
a.each_slice(3) # => #<Enumerator: [0, 1, 2, 3, 4, 5, 6, 7]:each_slice(3)>
a.each_slice(3).to_a # => [[0, 1, 2], [3, 4, 5], [6, 7]]

试试看

a.in_groups_of(3,false)

它会完成你的工作

也许我误解了这个问题,因为另一个答案已经被接受了,但是听起来好像你想把数组分成3个相等的组,不管每个组的大小,而不是像以前的答案那样把它分成 N 组,每组3个。如果您正在寻找这个方法,Rails (ActiveSupport)还有一个名为 团体的方法:

a = [0,1,2,3,4,5,6]
a.in_groups(2) # => [[0,1,2,3],[4,5,6,nil]]
a.in_groups(3, false) # => [[0,1,2],[3,4], [5,6]]

我不认为红宝石是等价的,但是,你可以通过添加这个简单的方法得到大致相同的结果:

class Array; def in_groups(num_groups)
return [] if num_groups == 0
slice_size = (self.size/Float(num_groups)).ceil
groups = self.each_slice(slice_size).to_a
end; end


a.in_groups(3) # => [[0,1,2], [3,4,5], [6]]

唯一的区别(正如您所看到的)是,这不会将“空白空间”分散到所有组中; 除了最后一个组之外,每个组的大小相等,而最后一个组总是保留剩余部分加上所有的“空白空间”。

更新: 正如@rimsky 敏锐地指出的那样,上面的方法并不总是能得到正确的组数(有时它会在最后创建多个“空组”,并将它们排除在外)。这是一个更新的版本,从 ActiveSupport 的定义中精简出来,它将额外的部分分散开来,以填充所要求的组数。

def in_groups(number)
group_size = size / number
leftovers = size % number


groups = []
start = 0
number.times do |index|
length = group_size + (leftovers > 0 && leftovers > index ? 1 : 0)
groups << slice(start, length)
start += length
end


groups
end

正如 Mltsy 写的,in_groups(n, false)应该做这项工作。

我只是想加点小技巧来保持平衡 my_array.in_group(my_array.size.quo(max_size).ceil, false).

这里有一个例子来说明这个技巧:

a = (0..8).to_a
a.in_groups(4, false) => [[0, 1, 2], [3, 4], [5, 6], [7, 8]]
a.in_groups(a.size.quo(4).ceil, false) => [[0, 1, 2], [3, 4, 5], [6, 7, 8]]

这需要一些更好的聪明才智来抹掉多余的部分,但这是一个合理的开始。

def i_need(bits, r)
c = r.count
(1..bits - 1).map { |i| r.shift((c + i) * 1.0 / bits ) } + [r]
end


>   i_need(2, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3, 5, 7], [2, 4, 6, 8]]
> i_need(3, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3, 5], [7, 2, 4], [6, 8]]
> i_need(5, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3], [5, 7], [2, 4], [6], [8]]