要素数ができるだけ均等になるように配列を分割する

例えば10個の要素を持つ配列があって、これを3つに分割したい時に、

a = [1,2,3,4,5,6,7,8,9,10]
n = 3
m = Rational(a.size, n).ceil
a.each_slice(m).to_a            #=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]

みたいにすると、3つには分割できるんですが、要素数が 4, 4, 2 と偏ってしまいます。これを例えば 4, 3, 3 のようにしたい。

a = [1,2,3,4,5,6,7,8,9,10]
n = 3
n.times.map{|i| a[a.size*i/n ... a.size*(i+1)/n]}
  #=> [[1, 2, 3], [4, 5, 6], [7, 8, 9, 10]]

…のようにやればできました。

なお、a.size よりも n の方が大きいと、結果に空配列を含みます。

a = [1,2,3]
n = 6
n.times.map{|i| a[a.size*i/n ... a.size*(i+1)/n]}
  #=> [[], [1], [], [2], [], [3]]

これが嫌な場合は最後に空配列を除外する感じで。

a = [1,2,3]
n = 6
n.times.map{|i| a[a.size*i/n ... a.size*(i+1)/n]}.reject(&:empty?)
  #=> [[1], [2], [3]]

追記

これは私が考えたわけではなくて、数年前に若い人に教えてもらったものです。

はじめ見た時、なんでこれでいいのかわからなかったんですが、単純にn分割した時の境界の小数点以下を切り捨てて整数にしてるだけです。

f:id:tmtms:20160728215136p:plain

図は10個を6分割した時の例です。

頭いいなー。