问题: 对给定的数组,拆分为指定个数的子数组,要求尽可能平均
我的实现是这样:
require 'matrix'
def split_group(arr, n)
Matrix.columns(
(arr + [nil] * (n - arr.size % n)).each_slice(n).to_a
).to_a.map(&:compact)
end
求更好的做法
Matrix.columns(x).to_a
可以换成 x.transpose
吧?
给定数组里带 nil
怎么办?
循环版:
i = 0
arr.group_by{ i+=1; i%n }.values
([arr.size / n] * (n - 1) << (arr.size / n + arr.size % n)).map { |i| a.shift(i) }
...
here:
a = [1, 2, 3, 4]
a.combination(1).to_a #=> [[1],[2],[3],[4]]
a.combination(2).to_a #=> [[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
a.combination(3).to_a #=> [[1,2,3],[1,2,4],[1,3,4],[2,3,4]]
我的生成的结果稍微整齐一点。虽然号称是最丑陋版。
def split_group(array, n)
size = array.size
div, mod = size.divmod(n)
new_array = array.each_slice(div).to_a
return new_array if mod == 0
x, y = new_array.take(n), new_array.drop(n).flatten
enum_x = x.cycle
enum_y = y.to_enum
loop { enum_x.next << enum_y.next }
x
end
何必太在意多出来一个或两个本地变量呢?你只要保证方法很小 (不超过 7 行), 并且只在方法内部使用本地变量就没问题呀。倒是问题在于:本地变量的命名,除了 x,y, 我实在是找不出好的名字,经常因为这个事情恼火。
说实话,我很佩服你动不动就一大长串,我反正是写不出来你那么长一串串的实现,头晕的要死。
a= (1..8).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8]
b = []
n = 3 # 拆成n个
count = (a.size/n).ceil # 每个子数组的元素)
count.times {|i| b << a[(i*count)...((i+1)*count)]}
b #=> [[1, 2, 3], [4, 5, 6], [7, 8]]
这样?貌似行数挺多……
a = (1..8).to_a
n = 3
b = []
(a.size.to_f / n).ceil.times{|i| b << a[(i*n)...((i+1)*n)]}
b
但是这样不能满足要求,比如 a 的 size 为 18,n 为 5,数组会拆成4,4,4,4,2
,而更平均的结果应该是4,4,4,3,3
@fsword 这样子吧,我还是喜欢思路简单的 我们设定个场景,分球到盒子里,要最平均的话,就是说轮流挨个往里放,这是基本想法。 但是这样顺序就变了(我有也不太明白顺寻变了好不好),不如计算下哪几个盒子放得多……
class Array
def equal_divise n
source = self.clone
size = self.size.to_f
result = []
n.times {|i| result << (source.pop i>=size%n ? (size/n).ceil : (size/n).floor)}
result.reverse
end
end
我写在类里面了,如果不在乎顺序,可以把 reverse 之类去掉…… 不过还是觉得行数有点多啊,求简化……
a = ('A'..'Z').to_a
#=> 26个字母的数组
a.equal_divise 4
#=> [["A", "B", "C", "D", "E", "F", "G"], ["H", "I", "J", "K", "L", "M", "N"], ["O", "P", "Q", "R", "S", "T"], ["U", "V", "W", "X", "Y", "Z"]]