patorashのブログ

方向性はまだない

Rubyで要素数が異なる二次元配列で行と列を入れ替える

最近のPRのレビューをしているときに、二次元配列のデータを入れ替える処理をしているところがあったので、レビュー後にチャットで意見交換していたら綺麗な感じにできたのでそれをメモして残しておく。

transposeを使うのがミソなのだけれど、transposeを使うには、配列の要素数を統一しなければならない。そのために、values_atを使う。このvalues_atを使うアイデアはパートナーさんが考えてくれた。

docs.ruby-lang.org

docs.ruby-lang.org

# 要素数が異なる配列を準備…
arr = [['a', 'b'], ['c', 'd', 'e', 'f'], [], ['g', 'h', 'i']]
# その中から最大要素数を取得
max_size = arr.map(&:size).max
# 各配列の要素数を最大要素数に合わせる
arr.map! {|it| it.values_at(0...max_size) }
# 行と列を入れ替える
arr.transpose
# => [
# ["a", "c", nil, "g"], 
# ["b", "d", nil, "h"],
# [nil, "e", nil, "i"],
# [nil, "f", nil, nil]]

最初はzipを使おうとしていたのだが、zipを使う場合は先頭要素に最も大きな配列がなければうまくいかないということを指摘してもらって、別のアイデアを考えていたら、こうなった。

縦持ちと横持ちのデータの入れ替えは時々したくなることがあるので、いざと言う時にこの記事を思い出したい。