配列


数値や文字列など、これまで習ったデータ型の場合は、一つのオブジェクトは一つだけの値を表す。たとえば、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 です。

配列のメソッド

以下は配列の操作によく使うメソッドを紹介する。


本日の課題

 基本課題 

受けたテストの数とそれぞれのテストの点数(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

ソースコード:
...

実行結果:
...

 発展課題 

  1. test_grades.rb を、各成績をとった回数と割合も出力するように改良すること。
  2. test_grades.rb を、点数の中央値も出力するように改良すること。
  3. ユーザーが5つの数字を入力し、その中から最小値と最大値を除外して残りの値の平均を計算するプログラムを作成すること。

目次