みずりゅの自由帳

主に参加したイベントやソフトウェア技術/開発について記録しています

rubyの配列の展開を勘違い。配列とpushと*とflattenと私。

備忘。

rubyのコードで、以下の解釈がすぐにできなかったので、忘れないように記録しておく。

newarray.push(*array.flatten)

とりあえずこのコードが何をしているかと言えば、以下になる。
なお、「array」と「newarray」は配列である。

  • arrayをflatten平坦化した配列(=配列中の配列要素が無くなった状態の配列)を作成
  • 「*」(アスタリスク)で「array.flatten」によって作成された平坦化された配列を配列展開splat展開)する
  • *array.flatten」で展開された複数の要素を、配列newarrayの末尾に追加する

結局のところ、要素中に配列を含む配列であるarrayをflattenで平坦化した配列にして、その配列の各々の要素(=複数要素)を配列newarrayに対してpushメソッド経由で追加した、ということだった。

言葉だけだとわかりづらいので、コードにしてみる。

まず、最初にarrayとnewarrayの用意。

arrayについては、配列の要素の配列を含む形になっている。
具体的には、「1」と「[2,3,[4]]」「5」を要素にもつ配列である。
加えて、「[2,3,[4]]」は「2」と「3」と「[4]」を要素にもつ配列でもある。

array = [1, [2, 3, [4]], 5]
#=> [1, [2, 3, [4]], 5]

newarrayについては、元から平坦化された配列で作成する。
ただし、pushの動作も再確認したいので、pushしながら配列を作成。
複数要素を渡した際には、各々の要素が追加されるというのがわかる。

newarray = [0]
#=> [0]

newarray.push(6)
#=> [0, 6]

newarray.push(7,8,9)  #<- 複数要素「7,8,9」を渡すと要素を1つずつ順に追加していく
#=> [0, 6, 7, 8, 9]

newarray
#=> [0, 6, 7, 8, 9]

余談だが、pushの引数に配列を渡せば、それはそのまま要素として追加される。

 anatherarray = [0]
#=> [0]

anatherarray.push(6)
#=> [0, 6]

anatherarray.push([7,8,9])
#=> [0, 6, [7, 8, 9]]

続いて、flattenメソッドの動き。
arrayに対してflattenを実行すると、以下のようになる。 引数なしで実行したflattenは再起的に全ての要素が平坦化されるまで処理を繰り返す。

array
#=> [1, [2, 3, [4]], 5]

array.flatten
#=> [1, 2, 3, 4, 5]

お次は、配列展開の「*」。 これも、コードにするとわかりやすい。

# 配列展開しない場合、配列の要素が配列になっている
[0, [1, 2, 3, 4, 5], 6]
#=> [0, [1, 2, 3, 4, 5], 6]

# 配列展開した場合、配列の要素がそれぞれ内側の配列の要素だったものだけになっている。
[0, *[1, 2, 3, 4, 5], 6]
#=> [0, 1, 2, 3, 4, 5, 6]

ここまでで、「push」「*」「flatten」の動きがわかった。
ということで、合体!

newarray.push(*array.flatten)
#=> [0, 6, 7, 8, 9, 1, 2, 3, 4, 5]

こいつを少しずつ解体していく。

newarray.push(*[1, [2, 3, [4]], 5].flatten)
#=> [0, 6, 7, 8, 9, 1, 2, 3, 4, 5]
newarray.push(*[1, 2, 3, 4, 5])
#=> [0, 6, 7, 8, 9, 1, 2, 3, 4, 5]
newarray.push(1, 2, 3, 4, 5)
#=> [0, 6, 7, 8, 9, 1, 2, 3, 4, 5]

結局は、以下と同じ結果になる。

 [0, 6, 7, 8, 9].push(1, 2, 3, 4, 5)
#=> [0, 6, 7, 8, 9, 1, 2, 3, 4, 5]