Rubyの二次元配列
これは「フィヨルドブートキャンプ Part 1 Advent Calendar 2020」の7日目の記事です。
昨日は、Sakiさんの 「初めて輪読会をやってみたらいいことばかりだったので、良かったことをまとめました 」でした。
Part. 2 もあります。
私はWebエンジニアに転職したいと思い、現在フィヨルドブートキャンプで学んでいます。
そのフィヨルドブートキャンプで、Advent Calendarの企画が立ち上がりました。
私はAdvent Calendarに参加するのは初めてなのですが、アウトプットを現在意識しているため書いてみることにしました。
とはいえ、Rubyのプラクティスに入ったばかりで何を書いたらいいのか迷いました。
先日、Unixのcalコマンド(カレンダー表示)をRubyで実装するプラクティスを行った際に、Rubyにおける二次元配列について少し調べたので、そのことを書くことにしました。
カレンダーつながりですね!☺️
Ruby初心者ですので、暖かい目で読んでいただけると助かります。
一次元配列
まず、一次元配列から考えます。
(参考:「スラスラ読める Rubyふりがなプログラミング」「ゼロからわかる Ruby 超入門」)
配列は要素として複数のオブジェクトをまとめて扱うクラスです。
オブジェクトとして、数値や文字列を扱います。
そして、配列自身もまた、オブジェクトです。
オブジェクトの種類のことをクラスと言います。
作成
配列を作成します。
wdays = ["月", "火", "水", "木", "金", "土", "日"]
要素を取得する
配列内の要素を取得する時は、インデックス(添え字)を使います。
puts wdays[2]
とすると
と表示されます。
配列全体を表示する時は、
puts wdays
とすると、
と各要素が縦に表示されます。
要素書き換え
配列の要素を書き換える時は、
wdays[1] = "雨"
puts wdays
とすると
と配列の要素が変わっています。
その他のメソッド
配列はArrayというクラスの一つで、元々色々便利なメソッドが備わっています。
(参考 Ruby 2.7.0 リファレンスマニュアル>ライブラリ一覧>組み込みライブラリ>Arrayクラス)
Arrayクラスの主なメソッド
メソッド | 働き |
---|---|
配列.first | 配列の最初の要素を返す |
配列.last | 配列の最後の要素を返す |
配列.push(要素) | 配列の末尾に要素を追加する |
配列.unshift(要素 | 配列の先頭に要素を追加する |
配列.delete(値) | 配列から値と一致する要素を全て削除する |
配列.shift | 配列の先頭から要素を1つ削除し、削除した要素を返す |
配列.pop | 配列の末尾から要素を1つ削除し、削除した要素を返す |
配列1 + 配列2 | 2つの配列の要素をつなげた配列を作る |
配列1 - 配列2 | 配列1から配列2の要素を削除した新しい配列を作る |
配列.size | 配列の要素数を返す |
配列.sum | 配列の全要素の合計を返す |
配列.sample | 配列からランダムに要素を取得する |
配列.shuffle | 配列をランダムに並び換える |
配列.sort | 配列の要素を順に並び換える(数値:小さい順、文字列:abc順) |
配列.sort.reverse | 配列の要素の並びが逆順になる(数値:大きい順、文字列:cba順) |
配列.join | 配列中の文字列を連結する |
初めから色々揃っていて便利ですね!
例1:deleteメソッド
例えば、deleteメソッドを使ってみます。
wdays.delete("雨")
puts wdays
"雨"が消えています!
例2:revereseメソッド
reverseメソッドがややこしかったので詳しく書きますと、
① 要素が数値の場合
p [4, 2, 8].sort
p [4, 2, 8].sort.reverse
p[4, 2, 8].reverse
reverseだけだと、先頭だけ逆順になり、全体はうまく並ばないので注意が必要です。
reverseだと、ただひっくり返った逆順になります。
(指摘していただき訂正しました! 2020.12.08)
② 要素が文字列の場合
p ["midori", "aka", "kiiro"].sort
p ["midori", "aka", "kiiro"].sort.reverse
p["midori", "aka", "kiiro"].reverse
reverseだけだと、同様に、先頭だけ逆順になり、全体はうまく並ばないので注意が必要です。
reverseだと、同様に、ただひっくり返った逆順になります。
(指摘していただき訂正しました! 2020.12.08)
例3:joinメソッド
joinメソッドは、配列の各要素をつなげるだけでなく、つなげるときに間へ入れる文字を指定できます。
puts ["空", "海", "太陽"].join("と")
二次元配列
配列は複数のオブジェクトを要素として扱うことができる。
配列自身もまたオブジェクトである。
それなら、配列の中で配列を要素として持てるはず…。
ということで、Rubyでは二次元配列も可能になっています。
しかし、どうやって作ればいいのだろう…。
calendar = [["1月1日", "1月2日", "1月3日"], ["2月1日", "2月2日", "2月3日"], ["3月1日", "3月2日", "3月3日"]]
とすれば初期化された二次元配列を作成することができ、
puts calendar[0][2]
puts calendar[2][1]
とすれば、各要素を表示することがわかりました。
でも、宣言はどうやってするのだろう...?
色々調べた結果、配列の宣言と初期化はnewメソッドを使えばできるようです。
calendar = Array.new(3, " 月 日")
calendar[2] = "2月1日"
puts calendar
できています!
それでは、二次元配列は、配列の中に要素として配列を持つのだから、こう書けばいいのかしら…
calendar = Array.new(3, Array.new(3, 0))
p calendar
calendar[0][1] = 2
puts calendar
…残念。初期化はうまくいっていますが、[0][1]要素に代入したことにより、[0][1]、[1][1]、[2][1]全ての要素が変化しています。
この書き方だと、[0]、[1]、[2]の要素が全て同じ配列オブジェクトを参照するようになっているようです。
(参照:Rubyで二次元配列の初期化)
それでは、どう書けばいいかというと、結論は、
calendar = Array.new(3) { Array.new(3, 0) }
とし、Array.newにブロックを渡せば、0で初期化された3x3の二次元配列を作成することができるとわかりました。
p calendar
calendar[0][1] = 2
puts calendar
初期化がうまくいっていて、代入した後も、[0][1]要素しか変化していません!
Rubyの標準ライブラリには多次元配列はなく、配列をネストすることで代用できます。特定の値で初期化するには、ブロック付きで「Array#new」を使用します。
ただし、ネストした配列は代用品に過ぎず、範囲を超えたインデックスに代入したときに問題があります。本書では「擬似多次元配列」と呼ぶことにします。
数値計算が目的ならばNArrayクラスを、行列計算が目的ならばMatrixクラスやVectorクラスを使用しましょう。
(参考:「改訂2版 Ruby逆引きハンドブック」)
ここまでたどりつくのが結構大変でしたので、ブログ記事に残すことができて良かったです!