プログラミングの仕事では、Rubyに限らず2次元の配列を使ったプログラムをよく利用します。Rubyが使えるプログラマーとして働くなら配列の使い方を学んでおきましょう。
とはいえRubyにおける2次元配列の特性を知らないと、仕事では使えません。今回は、Rubyにおける2元配列の作り方と、その際に気を付けたい注意点について解説します。
- 2次元の配列は配列の入れ子
- 空の2次元配列を作るならArray.new(Array.new())
- 配列から2次元配列を作るならpushメソッドを使う
- 配列をコピーする場合、=演算子とdupメソッドの2つの使い方があるので注意
2次元配列の基本
2次元配列とは、簡単に言えば配列の中の要素が配列という、入れ子の構造を持つ配列です。そして、Rubyに限らず多くのプログラムで2次元配列が使われています。
とはいえ、2次元配列が何か知らないとプログラムの中では使えません。そこでまずは、2次元配列の特徴について解説します。
表をイメージしてみよう
データを見やすくする方法として表がよく使われます。なお表とは、縦と横の罫線で格子状に区切った枠にデータを記入したものです。この表をプログラムの中で扱うには、どうすれば良いでしょうか。
例えば表の枠の分だけ変数を作ったり、全てのデータを1つの配列に入れて処理することも可能です。しかし、そのような方法は不便なうえ、プログラムも複雑になるでしょう。
そこで表の1行を1つの配列にし、その配列を列の数だけ作れば、プログラムの繰り返し処理などで簡単に扱えます。このように、表として表現される数値や文字をデータとしてプログラムで扱うための入れ物が2次元の配列です。
2次元配列の作り方
2次元配列を作るには、表をイメージした場合の1行分の配列を用意し、それを配列の要素とした入れ子の構造の配列です。そのため、2次元配列を作るには、まずは1次元の配列を用意し、それを配列の要素として追加していきます。
例えば次のような1次元の配列があったとします。
[1, 2, 3, 4, 5]
この1次元配列を要素とした配列を作ると、次のような2次元の配列を作れます。
[ [1, 2, 3, 4, 5], [1, 2, 3, 4, 5] ]
Rubyにおける1次元配列と2次元配列の比較
Rubyでは配列のメソッドが幾つも用意されているので、実際のプログラムでもよく利用されます。次にRubyで1次元の配列を宣言する方法と、2次元の配列を宣言する方法を紹介します。
なおRubyでは配列を作成する場合、[]の中に要素を記述します。下の例で1次元配列を作成するケースが解り易いでしょう。そして、2次元の配列では、要素として1次元の配列を使います。これが配列の入れ子の構造です。
Rubyで宣言した1次元の配列の例
row = [1, 2, 3, 4, 5]
Rubyで宣言した2次元の配列の例
table = [ [1, 2, 3, 4, 5], [1, 2, 3, 4, 5] ]
Rubyにおける2次元配列の作り方
Rubyには配列を作る方法が複数あるので、それらの方法を使って2次元の配列が作れます。ただし、その全てが実際のプログラミングで使いやすい訳ではありません。データの作り方によって、よく使われる方法が限られています。
次から、Rubyのプログラムで使われることの多い2次元配列の作り方を紹介します。
固定データを2次元配列として定義する
先ほどの1次元配列と2次元配列の比較で紹介した書き方が、Rubyにおける固定データを2次元配列として定義する方法です。
Rubyで宣言した2次元の配列の例
unit = [ ["mm", 0.001], ["cm", 0.01], ["m", 1], ["km", 1000] ]
全て同じデータの2次元配列を作る
配列を作る方法は先ほどの[]の他に、Arrayクラスのnewメソッドを利用する方法もよく使われます。そしてこの方法を利用することで、全て同じデータの配列を作ることが可能です。
例えばArrayクラスのnewメソッドにより全ての要素が0の1次元の配列を作る場合、次のように書きます。
row0 = Array.new(5,0) p row0 # [0, 0, 0, 0, 0]が表示される
同じように全ての要素が0の2次元配列を作る場合は、次のように書きます。
tbl0 = Array.new(2, Array.new(5,0)) p tbl0 # [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]]が表示される
配列を新規に定義するArrayクラスのnewメソッドは、引数として要素の数と値を指定できます。そして2次元の配列を作る場合、要素の値としてArrayクラスのnewメソッドによる要素が全て0の配列を指定しています。
1次元の配列を追加する
2次元の配列にその要素と同じ構造の1次元の配列を追加することで2次元配列が作れます。具体的にはRubyの配列に要素を追加するメソッドのpushを利用し、要素として1次元の配列を追加する方法で、次のように書くことが可能です。
row1 = [1,2,3,4,5] row2 = [6,7,8,9,10] tbl = [] tbl.push row1 tbl.push row2 p tbl # [[1,2,3,4,5], [6,7,8,9,10]]が表示される
この例は、1次元の配列row1とrow2を、配列に要素を追加するメソッドのpushにより2次元の配列tblに追加し、それを表示するプログラムです。
Rubyを学びたい方におすすめのスクールはこちら
Rubyで2次元配列を作る際の注意
先ほど紹介した1次元の配列を利用して2次元の配列を作る場合、配列のコピーでは一般的な変数のコピーと扱いが違う点に注意しなければなりません。しかし、Rubyにおける配列のコピーの扱いを知らない方もいるでしょう。
そこで次からRubyにおける配列のコピーの特徴と、2次元配列を作る際の注意点を解説します。
配列のコピーの基本
ほとんどのプログラム言語で配列をコピーする場合、メモリーに新しい格納領域を確保して、元の配列のデータをその領域にコピーします。しかし、Rubyには参照渡し、浅いコピー、深いコピーの3種類のコピーの方法があり、完全にコピーされる訳ではありません。次にこの3つのコピー方法の特徴を紹介します。
参照渡し:=演算子でコピーした場合。オブジェクトがコピーされず、コピー元の配列の参照が作られます。
浅いコピー:dupメソッドでコピーした場合。オブジェクトのコピーが作られますが、frozenなどの属性の一部はコピーされません。
深いコピー:Marshalクラスを利用してコピーした場合。オブジェクトのコピーが作られ、frozenを含む全ての属性も同時にコピーされます。
つまり、=演算子で配列をコピーした場合、オブジェクトがコピーさせません。
もし=演算子で2次元配列を作ったら
1次元配列から2次元配列を作る際、pushメソッドを利用した方法を紹介しましたが、この方法でも=演算子によるコピーと同じように追加されます。
例えば下記の例を見てください。
2次元配列の作成に失敗する例
data = [] arr = [0, "sample", 0] (1..3).each { |x| arr[0] = x data.push(arr) } p data # [[3, "sample", 0], [3, "sample", 0], [3, "sample", 0]] が表示される
この例は、(1..3)で作成した[1, 2, 3]の配列の数字を使い、宣言してある1次元の配列arrを書き換えて配列dataにpushメソッドで追加し、2次元の配列を作る例です。しかし、arr[0]=xで[1, 2, 3]の順で書き換えているはずですが、全て同じ3が表示されます。
これは、2次元配列に追加された1次元配列は、全て同じarrを参照しているのが原因です。そのため、全ての要素が同じarrを参照し、最後にarr[0]に代入した値の3が表示されます。
そのためarrをそのまま追加するのではなく、dupメソッドの浅いコピーで別の配列に一旦コピーしてから2次元配列に追加する必要があるので、このような処理を作る場合は注意してください。
正しく2次元配列を作成する例
data = [] arr = [0, "sample", 0] (1..3).each { |x| tmp = arr.dup tmp[0] = x data.push(tmp) } p data # [[1, "sample", 0], [2, "sample", 0], [3, "sample", 0]] が表示される
まとめ
これまで説明したように2次元配列はRubyに限らずプログラムで使いやすいデータ形式です。また、2次元配列は、繰り返し処理を利用することで、1次元配列から簡単に作れます。
しかし、Rubyの配列をコピーする場合、参照渡し、浅いコピー、深いコピーの3種類のコピーの方法があり、=演算子のコピーは参照渡しのため、2次元配列が作れません。そのため繰り返し処理の中2次元配列を作る場合は、浅いコピーを作るdupメソッドを利用してください。
また、Rubyについてもっと詳しく学びたい方は、ポテパンキャンプの利用を検討されてはいかがでしょうか。
Rubyを学びたい方におすすめのスクールはこちら