動かざることバグの如し

近づきたいよ 君の理想に

Rubyで配列をn分割する方法

スプラで待機している最中に考えてた。

その時は自分含めて5人いて、2人と3人にチーム分けしたかったのだが、それをRubyの1ライナーでやりたい。どうしようか

5人をAさん〜Eさんとする。ここまでは共通だと思う。

%w(Aさん Bさん Cさん Dさん Eさん).shuffle

方法1 group_byを使う

irb(main):016:0> %w(Aさん Bさん Cさん Dさん Eさん).shuffle.group_by.with_index{|a,i| i % 2 == 0}
=> {true=>["Aさん", "Bさん", "Eさん"], false=>["Dさん", "Cさん"]}

こっちのgroup_byRailsの方ではなく組み込みの方。with_indexでindexが取れるのでその値が偶数か奇数かで2分割する。シンプルではあるが、2分割にしかできないのがキズ

group_byの代わりにpartitionでも可

irb(main):037:0> %w(Aさん Bさん Cさん Dさん Eさん).shuffle.partition.with_index{|a,i| i % 2 == 0}
=> [["Cさん", "Dさん", "Eさん"], ["Bさん", "Aさん"]]

方法2 in_groupsを使う

これはRailsのメソッドだが、配列をn分割してくれるメソッド。しゅごい

[14] pry(main)> %w(Aさん Bさん Cさん Dさん Eさん).shuffle.in_groups(2)
=> [["Bさん", "Cさん", "Eさん"], ["Aさん", "Dさん", nil]]

これなら仮に人数増えて分割する数を増やしたいってなっても対応できる(8人なら4x4で分ければええやんってのはナシで

[16] pry(main)> %w(Aさん Bさん Cさん Dさん Eさん Fさん Gさん Hさん).shuffle.in_groups(3)
=> [["Cさん", "Eさん", "Aさん"], ["Bさん", "Fさん", "Dさん"], ["Hさん", "Gさん", nil]]

失敗例1 each_slice

これでも一応できる。しかし、引数に配列の長さ/2を明示的に渡さないといけないので。。。

irb(main):031:0> %w(Aさん Bさん Cさん Dさん Eさん).shuffle.each_slice(3).to_a
=> [["Bさん", "Dさん", "Eさん"], ["Aさん", "Cさん"]]