数値や文字列など、これまで習ったデータ型の場合は、一つのオブジェクトは一つだけの値を表す。たとえば、String(文字列)を使って3つの名前をメモリに保持したい時は、それぞれの名前を別の変数に代入しなければならない。
name1 = "Peter"
name2 = "Anna"
name3 = "Mark"
なお、それぞれの名前の文字を全て大文字に変換し、番号を付けて出力し、さらにその文字数を表示したい場合は、(変数名以外は)同じソースコードを何回も記述する必要があり、非効率でバグが生じやすい。
name1 = name1.upcase # upcaseメソッドは文字列を大文字に変換する
printf("1番目の名前: %s\n", name1)
printf("文字数: %d\n", name1.length) # lengthメソッドは文字列の文字数を返す
name2 = name2.upcase
printf("2番目の名前: %s\n", name2)
printf("文字数: %d\n", name2.length)
name3 = name3.upcase
printf("3番目の名前: %s\n", name3)
printf("文字数: %d\n", name2.length) # ソースコードをコピペする時はこのようなバグが起こりやすい
結果:
1番目の名前: PETER
文字数: 5
2番目の名前: ANNA
文字数: 4
3番目の名前: MARK
文字数: 4
解説:最後の行で表示されるのは name3 ではなく name2 の文字数である。今回の例では「Anna」と「Mark」はどちらも4文字だからたまたま正しい結果になったが今後違う名前にすれば間違った結果が表示されるおそれがある。
上記の例のように、複数の値に対して同じ処理を行う場合は、コレクション(collection)と呼ばれるものを利用するべきである。コレクションとは、複数の値(オブジェクト)をまとめて保持できるデータ型である。今回はRubyのもっとも基本的なコレクションであるArray(配列)クラスを紹介する。
配列と前回習った繰り返し処理(ループ)を使って上記のプログラムを書き直してみよう。
練習問題 names_array.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
names = ["Peter", "Anna", "Mark"]
num = 1
for name in names do
name = name.upcase
printf("%d番目の名前: %s\n", num, name)
printf("文字数: %d\n", name.length)
num += 1
end
結果:
1番目の名前: PETER
文字数: 5
2番目の名前: ANNA
文字数: 4
3番目の名前: MARK
文字数: 4
解説:前回習ったように、for は複数の要素を持つオブジェクトの各要素を順番に変数に代入して処理を繰り返す。子の例では3つの文字列を含む配列(names)の要素を順番に name という変数に代入してそれぞれの名前を大文字に変換しその文字数を出力している。
新しい配列を作成する典型的な方法として、配列に保管する値をカンマで区切って、角括弧で全体を括って表記する。
products = ["パン", "チョコレート", "おにぎり"]
prices = [99, 150, 120]
配列に保管するデータの中身や個数が最初から決まっていない場合は、括弧の中に何も入れずに書くと空の配列を用意できる。
prices = []
配列に含まれる一個一個の値のことを要素という。配列の要素は順番が決まっている。各要素にはその位置を表す、インデックス(index)または添え字と呼ばれる番号がついている。numbers[3] のように、配列名(変数名)の直後に角括弧に囲んでインデックスを書くことによって、配列の特定の位置に値を入れたり、その位置に保持されている値を参照したりすることができる。配列のインデックスは0から始まる。
練習問題 array_indices.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
numbers = [1, 2, 3, 4]
printf("numbers[0] の値は %s です。\n", numbers[0])
printf("numbers[1] の値は %s です。\n", numbers[1])
printf("numbers[2] の値は %s です。\n", numbers[2])
printf("numbers[3] の値は %s です。\n", numbers[3])
結果:
numbers[0] の値は 1 です。
numbers[1] の値は 2 です。
numbers[2] の値は 3 です。
numbers[3] の値は 4 です。
配列に存在しないインデックスを参照しようとすると、エラーにはならないが、nil(値がない状態を表すオブジェクト)が返されるので、注意してください。例えば、上記の array_indices.rb に次のような一行のコードを追記して実行してみよう。
printf("numbers[4] の値は %s です。\n", numbers[4])
結果:
numbers[4] の値は です。
インデックスを使って配列に新しい要素を追加することもできる。
練習問題 populate_array.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
numbers = [] # 空の配列からスタート
# 要素を追加する
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
printf("numbers[0] の値は %s です。\n", numbers[0])
printf("numbers[1] の値は %s です。\n", numbers[1])
printf("numbers[2] の値は %s です。\n", numbers[2])
printf("numbers[3] の値は %s です。\n", numbers[3])
結果:
numbers[0] の値は 1 です。
numbers[1] の値は 2 です。
numbers[2] の値は 3 です。
numbers[3] の値は 4 です。
配列は前回習った繰り返し処理(ループ)と組み合わせて利用することが多い。
例1(while文で配列の要素を増やす):
練習問題 array_while.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
numbers = []
i = 0
while i < 5 do
numbers[i] = i+1
printf("%d番目の繰り返し。numbers[%d] に %d が格納されました。\n", i+1, i, numbers[i])
i += 1
end
結果:
1番目の繰り返し。numbers[0] に 1 が格納されました。
2番目の繰り返し。numbers[1] に 2 が格納されました。
3番目の繰り返し。numbers[2] に 3 が格納されました。
4番目の繰り返し。numbers[3] に 4 が格納されました。
5番目の繰り返し。numbers[4] に 5 が格納されました。
例2(for文で配列の要素を順番に出力):
練習問題 array_for.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
numbers = [7, 5, 11, 22, 150]
i = 1
for num in numbers
printf("%d番目の繰り返し。num の値は %3d です。\n", i, num)
i += 1
end
結果:
1番目の繰り返し。num の値は 7 です。
2番目の繰り返し。num の値は 5 です。
3番目の繰り返し。num の値は 11 です。
4番目の繰り返し。num の値は 22 です。
5番目の繰り返し。num の値は 150 です。
例3(eachメソッドで配列の要素を順番に出力):
練習問題 array_which.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
numbers = [7, 5, 11, 22, 150]
i = 1
numbers.each do |num|
printf("%d番目の繰り返し。num の値は %3d です。\n", i, num)
i += 1
end
結果:
1番目の繰り返し。num の値は 7 です。
2番目の繰り返し。num の値は 5 です。
3番目の繰り返し。num の値は 11 です。
4番目の繰り返し。num の値は 22 です。
5番目の繰り返し。num の値は 150 です。
以下は配列の操作によく使うメソッドを紹介する。
配列の長さ(要素の数)を返す。
例:
numbers = [1, 5, 15, 150]
puts numbers.length # 結果:「4」と表示される
配列の長さ(要素の数)を返す。length
メソッドと同じ。
配列の後ろに新しい要素を追加する。
例:
numbers = [7, 5, 1]
numbers.push(22) # 結果: numbers は [7, 5, 1, 22] になる
配列の先頭の要素を取り除いた上で、取り除かれた要素の値を返す。
例:
練習問題 array_shift.rb#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
numbers = [1, 5, 15, 150]
printf("最初は numbers の値は %s です。\n\n", numbers) # このように配列全体を文字列として表示できる
puts "num = numbers.shift のあとは、"
num = numbers.shift
printf("num の値は %s です。\n", num)
printf("numbers の値は %s です。\n\n", numbers)
puts "もう一度の num = numbers.shift のあとは、"
num = numbers.shift
printf("num の値は %s です。\n", num)
printf("numbers の値は %s です。\n", numbers)
結果:
最初は numbers の値は [1, 5, 15, 150] です。
num = numbers.shift のあとは、
num の値は 1 です。
numbers の値は [5, 15, 150] です。
もう一度の num = numbers.shift のあとは、
num の値は 5 です。
numbers の値は [15, 150] です。
配列の要素を小さい順に並べ換えた結果を返す。たとえば、
numbers = [7, 5, 1, 22]
nums_sorted = numbers.sort # 結果: nums_sorted は [1, 5, 7, 22] になる
sortは、元の配列のコピーを取ってから並べ換え作業をするので、numbers.sort としても、numbers 変数の値は変わらない。numbers 変数の値そのものの順番を壊して並べ換えたいときは
numbers = [7, 5, 1, 22]
numbers = numbers.sort # 結果: sort の結果を numbers に代入しなおす
もしくは
numbers = [7, 5, 1, 22]
numbers.sort! # 結果: numbers の要素を直接並べ替える(破壊的操作)
とする。元の値を直接操作することを破壊的操作という。
文字列を含む配列に対してsort
を使うと、辞書順に並べ換えた結果を返す。
#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
names = ["Peter", "Anna", "Mark", "John"]
names_jp = ["やまだたろう", "なかまちたろう", "いいもりはなこ", "あいたあきら"]
puts "sortの前:"
puts names # このように配列の全要素を(改行を挟んで)表示できる
puts names_jp
puts
puts "sortの後:"
puts names.sort
puts names_jp.sort
結果:
sortの前:
Peter
Anna
Mark
John
やまだたろう
なかまちたろう
いいもりはなこ
あいたあきら
sortの後:
Anna
John
Mark
Peter
あいたあきら
いいもりはなこ
なかまちたろう
やまだたろう
配列の要素の順序を逆にした配列を返す。たとえば、
numbers = [7, 5, 1, 22]
numbers_rev = numbers.reverse # 結果: numbers_rev は [22, 1, 5, 7] になる
sort, reverseを組み合わせると、逆順に並べ換えた結果が得られる。
names = ["Peter", "Anna", "Mark", "John"]
names = names.sort.reverse # 結果: names は ["Peter", "Mark", "John", "Anna"] になる
reverseもsort同様、元の変数の値は変わらない。変えたい場合は、reverse!メソッドを使う。
受けたテストの数とそれぞれのテストの点数(100点満点)をユーザーに入力してもらって、配列に保管し、それぞれのテストと平均点数との差および成績を出力するプログラムtest_grades.rbを作成せよ。
成績の基準:
平均90以上 → 秀
平均80点以上で90点未満 → 優
平均70点以上で80点未満 → 良
平均60点以上で70点未満 → 可
平均60点未満 → 不可
なお、ユーザーが入力した点数が100点を超えている場合は「100点以下の点数を入力してください」と表示し、前回の授業で紹介したredoを使って再度入力するようにしてください。
ヒント
2つのループが必要になる:
1)ユーザーがそれぞれのテスト点数を入力するループ
2)それぞれの点数の平均との差と成績を計算し表示するループ
実行結果の例:
sime{c11xxxx}% ruby test_grades.rb
受けたテストの数を入力してください
3
1回目のテスト点数を入力してください(100点満点)
70
2回目のテスト点数を入力してください(100点満点)
80
3回目のテスト点数を入力してください(100点満点)
180
100点以下の点数を入力してください!
3回目のテスト点数を入力してください(100点満点)
100
点数 平均との差 成績
70 -13.33 良
80 -3.33 優
100 16.67 秀
本文は下記の通り記入してください.
氏名: 苗字名前
学籍番号: C11xxxxx
ソースコード:
...
実行結果:
...
発展課題