【Ruby】一次元配列を二次元配列に変換する(多次元配列も)

要望

今手元にある一次元配列を、要素a個のN次元配列(多次元配列)に変換したい。

初期化の方法ではなく、すでに存在する配列をどうこうする。

理解の方針

今回は、まず2次元と3次元を取り扱い、多次元配列の理解を深める。

その後、帰納的にN+1次元を実現する。

N次元配列について

まずN次元配列についての理解を深める。

1次元配列

数直線を考えるとわかりやすい。

[1, 2, 3, ...]

2次元配列

X軸とY軸を考えるとわかりやすい。

2次元目の要素数は実は何個でもいい。

[
  [1, 2],
  [3, 4, 5],
  [6],
  ...
]

3次元配列

番地を想像するとわかりやすい。

[
  # 0番目
  [
     # 0-1
     [
       1, # 0-1-0
       2  # 0-1-1
   ], 
     # 0-1
     [
       3 # 0-1-0
     ] 
  ],
  # 1番目
  [
    [ 3, 4, 5],
    [6],
  ]
  ...
]

まとめると

  • some_array[x][y]でアクセスできるなら、2次元配列列。
  • some_array[x][y][z]でアクセスできるなら、3次元配列。

みために惑わされがち。

つぎにコードを書いていく。

2次元配列の場合

コード

p [1,2,3,4,5].each_slice(2).to_a

ワンライナーでチェック

ruby -e 'p [1,2,3,4,5].each_slice(2).to_a'

結果

[[1, 2], [3, 4], [5]]

each_sliceの使い方

docs.ruby-lang.org

3次元配列の場合

何個かの要素に分けたいので、elm_countに要素数を入れる

some_array[x][y][z]でアクセスできるなら、3次元配列。

yとzの個数の上限を設ける必要がある。

yの個数を2個、 zの個数を2個にした場合のイメージ

[
  [
    [1, 2],
    [3, 4]
  ],
  [
    [5, 6],
    [7, 8]
  ]
],
ruby -e '
max_elm_in_second_floor = 2
max_elm_in_third_floor = 2
array = [1, 2, 3, 4, 5, 6, 7, 8]
new_array = array.each_slice(max_elm_in_second_floor).each_slice(max_elm_in_third_floor).to_a

p new_array'

まとめ

N次元配列つくるときは、各階層の要素数を決める。

汎化すると、

def to_multidimensional(array, dimension, *each_floor_element)
  return array if each_floor_element.empty?
  sub_array_size = each_floor_element.reduce(:*) || 1
  array.each_slice(sub_array_size).map { |sub| to_multidimensional(sub, *each_floor_element) }
end

# 使用例
one_d_array = (1..8).to_a
dimension = 3
each_floor_element = [2, 2]  # 次元数

three_d_array = to_multidimensional(one_d_array, dimension, *each_floor_element)
p three_d_array

おまけ: webのruby実行環境

runrb.io