LoginSignup
17
8

More than 3 years have passed since last update.

【Ruby】Rubyにおける二次元配列の初期化と扱い方

Last updated at Posted at 2020-07-29

はじめに

Rubyのアルゴリズムを本気で学び始めた当初、二次元配列に苦しめられましたが、少しずつ扱いに慣れてきたので、備忘録&誰かの助けになればな...と思い書かせていただきます。

二次元配列とは?

配列の中に、配列が格納された形の配列のことです。
また2よりも更に大きい次元の配列を多次元配列と言います。

arr.rb
#一次元配列(通常の配列)
colors = ["Red", "Green", "Blue"]

#二次元配列
colors = [["Red", "Green", "Blue"], ["Yellow", "Purple", "Orange"]]

二次元配列の初期化の方法

二次元配列を初期化(生成)する上で一つ注意点があります。

以下を参照ください。

arr.rb
arr = Array.new(2, Array.new(3, 0))
#=> [[0, 0, 0], [0, 0, 0]]

一見、二次元配列になっているのですが、実はこれ、二次元目の配列が全て同一のオブジェクトとして生成されてしまっています。
試しに配列の値を変更してみます。

一つ目の要素(配列)の中の、真ん中の要素に「1」を代入してみます。

arr.rb
arr = Array.new(2, Array.new(3, 0))
p arr
#=> [[0, 0, 0], [0, 0, 0]]

arr[0][1] = 1
p arr
#=> [[0, 1, 0], [0, 1, 0]]

#期待していた出力
#=> [[0, 1, 0], [0, 0, 0]]

このようにarr[0]に対して行った代入が、別の要素にまで代入されています。

これは最初の初期化の時点で、別々のオブジェクトとして定義できていないことによって起こります。

個別のオブジェクトとして生成する方法

ブロックを渡すことにより生成します。

arr.rb
arr = Array.new(2) { Array.new(3,0) }
p arr
#=> [[0, 0, 0], [0, 0, 0]]

arr[0][1] = 1
p arr
#=> [[0, 1, 0], [0, 0, 0]]

※補足
よりわかりやすい説明のコメントいただきましたのでそのまま引用させていただきます。
@kts_h さんありがとうございます。

メソッドの引数は、メソッド呼び出しの際に一度だけ評価されるので、Array.new(3, 0) を評価して得られた同一のArray オブジェクトが外側の配列の全ての要素になってしまうのに対し、ブロック付きメソッドのブロックは、反復するたびに評価されることがあり、Array.new { |i| ... } はその一例であるため、外側の配列の要素を作るたびに Array.new(3, 0) が評価されて、その都度、異なる Array オブジェクトが作成され、外側の配列の要素になることを明示すると、ほかの初心者の人たちに対し、より親切な説明になるのではないかと思いました。

二次元配列の操作について

一次元配列とは違い、二次元配列は次元が深くなっていて、一見複雑にも見えるのですが、非常に直感的に操作できます。

代入

初期化の際にも行いましたが、代入は以下のように行います。

arr.rb
arr = Array.new(2) { Array.new(3,0) }

arr[0][0] = 1
p arr
#=> [[1, 0, 0], [0, 0, 0]]

arr[1][2] = 1
p arr
#=> [[0, 0, 0], [0, 0, 1]]

繰り返し処理(each)

次に繰り返し処理での、扱い方です。
今回は「eachメソッド」を使用します。

arr.rb
arr = Array.new(3) { Array.new(3,0) }
arr.each do |p_a|
  p p_a
end

#=>
[0, 0, 0]
[0, 0, 0]
[0, 0, 0]

#一番深い次元の要素を一つずつ出力する場合
arr = Array.new(3) { Array.new(3,0) }
arr.each do |p_a|
  p_a.each do |c_a|
    p c_a
  end
end

#=>
0
0
0
0
0
0
0
0
0

このように繰り返し処理を二重にかけることで、一番深い要素一つ一つにアクセスできました。

二次元配列は慣れるとロジックを組む上で便利です。
例えば、配列の中の数値でFizzBuzzを行う場合

arr.rb
int = 1
arr = Array.new(10) { Array.new(3, 0) }
arr.each_with_index do |p_a, p_index|
  p_a.each_with_index do |c_a, c_index|
    if int % 15 == 0
      arr[p_index][c_index] = "FizzBuzz"
    elsif int % 5 == 0
      arr[p_index][c_index] = "Buzz"
    elsif int % 3 == 0
      arr[p_index][c_index] = "Fizz"
    else
      arr[p_index][c_index] = int
    end
    int += 1
  end
end

p arr
#=>
[[1, 2, "Fizz"], [4, "Buzz", "Fizz"], [7, 8, "Fizz"], 
["Buzz", 11, "Fizz"], [13, 14, "FizzBuzz"], [16, 17, "Fizz"], 
[19, "Buzz", "Fizz"], [22, 23, "Fizz"], ["Buzz", 26, "Fizz"], 
[28, 29, "FizzBuzz"]]

このように非常に直感的に操作することができます。

※コードは非常に助長だと思います。ゴメンナサイ

ご指摘等ありましたらズバズバとお願いいたします。

17
8
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
8