配列オブジェクト
配列オブジェクト
配列オブジェクトはハッシュと同じように、1つの変数でたくさんの情報を持つことのできるオブジェクト。
配列の中にはたくさんのオブジェクトを入れることができる。ハッシュがキーでオブジェクトを管理していたのに対して、配列は順番でオブジェクトを管理する。
配列は箱をイメージしてください。この箱の中にはいろんな情報を何個でも入れることができる。
箱の中に本を積み重ねると下から順番になる。このように配列もデータを入れるとそのデータに順番がつけられる。すなわちデータと順番がひもづけられる。
要素
配列の中のデータは要素と呼ばれる。要素は順番を持っていて、配列に入れた順に1番目,2番目..と自動的に順番が割り振られる。
配列オブジェクトを生成する
配列を作るもっとも簡単な方法。
1 |
配列オブジェクト = []
|
これで何も入っていない空の箱の配列ができる。
ハッシュは{}(中括弧)で囲んでいたのに対し、配列は[](大括弧)で囲む。
もちろん、最初から要素を入れた状態で作ることもできる。文字列「ペン、消しゴム、定規」の入った配列オブジェクト「pencil_case」をつくってみる。
1 2 |
pencil_case = ["ペン", "消しゴム", "定規"]
puts pencil_case
|
ここでは最初に書いた要素の方が早い順番になる。つまり、ペンが1番目、消しゴムが2番目、定規が3番目。
配列オブジェクトに要素を追加
<<メソッド
生成した配列オブジェクトに新しい要素を追加したいときがある。そのときは<<メソッドを使って、以下のように追加ができる。
1 |
配列オブジェクト << 追加する要素
|
先ほどの配列オブジェクト「pencil_case」に文字列「メモ帳」を追加する。
1 2 3 |
pencil_case = ["ペン", "消しゴム", "定規"]
pencil_case << "メモ帳"
puts pencil_case
|
puts pencil_caseでは「メモ帳」も表示されるのでちゃんと追加されているのがわかる。<<メソッドで追加すると配列の一番最後にその要素が追加される。
配列の要素の数をカウントする
lengthメソッド
lengthメソッドはその配列の中にある要素の数を返してくれるメソッド。
1 |
配列オブジェクト.length # => 配列オブジェクト内の要素の数
|
1 2 3 4 5 6 |
pencil_case = ["ペン", "消しゴム", "定規"]
puts pencil_case.length
pencil_case << "メモ帳"
pencil_case << "付箋"
puts pencil_case.length
|
最初は「ペン、消しゴム、定規」という3つの要素が入っているので、3がlengthメソッドで返ってくる。その後「メモ帳、付箋」を追加したので5が返ってくる。このようにlengthメソッドを使えば配列の要素の個数がすぐにわかる。
レビューの情報を配列オブジェクトで管理
- 複数のレビューの情報を持った配列オブジェクト「posts」を定義する
- 1つのレビューは今まで通り、ハッシュオブジェクト「post」で生成する
- レビューを書いたらハッシュオブジェクト「post」を配列オブジェクト「posts」に追加する
これで、書いたレビューが次々に配列オブジェクトに入れられていく。
配列オブジェクトpostsを生成
まずは、レビュー情報を管理する配列オブジェクトpostsを生成する。生成は以下のコードで行う。
1 |
posts = [] # 複数のレビューを持つ配列オブジェクト
|
始めはレビューの情報は何もないので、この生成方法になる。
この一行をreviewApp.rbの
- 繰り返し処理whileよりも前(while文の外)
に書く。
whileで繰り返されている処理の中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
while true do
posts = [] # 配列オブジェクトpostsの生成
# メニューの表示
puts "レビュー数:0"
puts "[0]レビューを書く"
puts "[1]レビューを読む"
puts "[2]アプリを終了する"
input = gets.to_i
if input == 0 then
post_review # post_reviewメソッドの呼び出し
elsif input == 1 then
read_reviews # read_reviewsメソッドの呼び出し
elsif input == 2 then
end_program # end_programメソッドの呼び出し
else
exception # exceptionメソッドの呼び出し
end
end
|
としてしまうと、メニューが表示されるたびに配列が空になってしまう。
1 |
posts = [] # 空の配列を生成する
|
せっかくレビューを複数管理したいのに配列が空になれば当然レビューは消えてしまう。
次に、どれかのメソッドの中(postReviewなど)だが、これも結局posts = []
を書いたどれかのメソッドが呼ばれるたびに配列が空になってしまう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
def post_review
posts = []
# 変数の定義
post = {}
puts "ジャンルを入力してください:"
post[:genre] = gets.chomp
puts "タイトルを入力してください:"
post[:title] = gets.chomp
puts "感想を入力してください:"
post[:review] = gets.chomp
line = "---------------------------"
# レビューの描画
puts "ジャンル : #{post[:genre]}\n#{line}"
puts "タイトル : #{post[:title]}\n#{line}"
puts "感想 :\n#{post[:review]}\n#{line}"
end
# post_reviewを呼ぶたびに
# posts = []
# となり、配列が空になってしまう
|
よって、プログラムが実行されてから一回しか呼ばれない場所の
while文よりも前、ということになる。
配列オブジェクトpostsにレビューの情報postを追加
あとは「レビューを書く」で生成したレビューのハッシュオブジェクトpostを配列postsに追加するだけ。
reviewApp.rb
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
def post_review
# 変数の定義
post = {}
puts "ジャンルを入力してください:"
post[:genre] = gets.chomp
puts "タイトルを入力してください:"
post[:title] = gets.chomp
puts "感想を入力してください:"
post[:review] = gets.chomp
line = "---------------------------"
# レビューの描画
puts "ジャンル : #{post[:genre]}\n#{line}"
puts "タイトル : #{post[:title]}\n#{line}"
puts "感想 :\n#{post[:review]}\n#{line}"
end
## 以下省略
|
post_review
メソッドの中では新しいレビューの変数postを生成している。これを配列postsに追加したいので、<<メソッド
を使用する。
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
def post_review
# 変数の定義
post = {}
puts "ジャンルを入力してください:"
post[:genre] = gets.chomp
puts "タイトルを入力してください:"
post[:title] = gets.chomp
puts "感想を入力してください:"
post[:review] = gets.chomp
line = "---------------------------"
# レビューの描画
puts "ジャンル : #{post[:genre]}\n#{line}"
puts "タイトル : #{post[:title]}\n#{line}"
puts "感想 :\n#{post[:review]}\n#{line}"
# 配列オブジェクトに追加
posts << post
end
## 以下省略
|
しかし、このソースコードはエラーになってしまう。なぜならばpost_reviewメソッドの中では変数postsが使えないから。
変数のスコープ
変数には、その変数が使える範囲というものが決まっている。これをスコープという。通常、メソッド内ではそのメソッド内で定義した変数しか利用することができない。
スコープ
ある変数を利用できる範囲のこと。スコープの範囲外の変数を使おうとすると、エラーが起こる。
さきほどのエラーは、変数postsにとってpost_reviewメソッドがスコープ外であるために起きた。
ではどのようにして変数のスコープが決まるのか。
変数のスコープの例
以下のコードは、同じスコープの範囲内にあると言える(スコープが異なる範囲が存在しない)。こちらを実行すれば、2行目のputs
によって問題なくターミナルに「東京」と表示される。
スコープの範囲内のため、正常に動作する
1 2 |
capital = "東京" # 首都は「東京」
puts capital
|
しかし、次のコードは、スコープの違う範囲にある変数を利用しようとしているため、エラーが起こる。
スコープの範囲が違うため、エラーになる
1 2 3 4 5 6 7 |
capital = "東京" # 首都は「東京」
def america
puts capital
end
america # エラー
|
americaというメソッドを作って、その中で1行目の変数capital
をputsしようとしている。しかし、メソッド内ではメソッド内で定義した変数しか使えない。
以下の例では、同名ですがスコープの範囲が違う場所でそれぞれ定義した変数の挙動を確かめられる。
同名でもスコープの範囲が違う変数
1 2 3 4 5 6 7 8 |
capital = "東京" # 首都は「東京」
def america
capital = "ワシントン" # americaの首都は「ワシントン」
puts capital
end
america # => ワシントン
|
メソッドamerica
内4行目で変数capital
を生成している。こちらは"ワシントン"という文字列。このファイルを実行すると、最終的には5行目のputsで"ワシントン"と表示される。1行目で変数capital
という同じ名前で中身は"東京"の変数を定義しているが、メソッドamerica
内では4行目につくった変数capital
が使われる。