成績処理の例

配列を利用して、試験の得点の処理をするプログラムを作成してみよう。 国語の試験の結果ファイルとして以下のようなデータを作成しよう。

score.txt

山田太郎	50
中町太郎	90
飯森花子	91
鶴岡一人	60
酒田三吉	52
三川一二三	12

このデータを読み込み、全員の平均点を計算したうえで、個人個人の 平均点との得点差も合わせて出力するようなプログラムを作ってみよう。

平均点を計算するためには、まず全員のデータを読み込んで、得点と人数を 求める必要がある。さらに、個人個人の平均点との差を出力するためには、全員 の得点を記憶しておく必要があるので、配列に、 名前・得点を入れておかなければならない。

まず最初に、データファイルを全部読み、名前と得点を配列に記憶しよう。 データを全部読むループは次のように書ける。

while yomikomi=gets
  :
end

この中に、名前と得点を切り出して変数に入れる部分を入れる。 名前と得点の切り出しには正規表現のグルーピングを利用する。

/(\S+)\s+(\d+)/ =~ yomikomi

括弧で括った N個目の文字列は、変数 $N で取り出すことができる。yomikomiの持つ文字列が正規表現に マッチした場合、 (\S+) つまり非空白文字の連続が、$1に入り、 (\d+) つまり数字の連続が、$2に入る。これを利用して 配列への格納を以下のようにする。

while yomikomi=gets
  if /(\S+)\s+(\d+)/ =~ yomikomi
    名前用の配列に $1 を追加
    得点用の配列に $2.to_i を追加
  end
end

名前用、得点用2つの配列を用意するとともに 合計得点を記録する変数を加えるようにした上で、 これをRubyプログラムに直すと以下のようになる。

name  = []
score = []
sum = 0
while yomikomi=gets
  if /(\S+)\s+(\d+)/ =~ yomikomi
    name << $1
    score << $2.to_i
    sum += $2.to_i
  end
end

これで変数 sum に合計点が入り、 配列の length メソッドで要素数、すなわち 人数が分かるので平均点が計算できる。

average = sum.to_f/score.length		# name.lengthで割ってもよい

割り算をする場合は整数をto_fメソッドで 浮動小数点数に変換することを忘れないようにしよう。

最後に、全員の、氏名、得点、平均点との差、をループで出力する。

i = 0
print "--氏名--------------+-得点-+-平均との差--\n"
while i < score.length
  printf("%-20s %5d   %5.1f\n", name[i], score[i], score[i]-average)
  i += 1
end

添字変数 i を自動的に増やす以下の方法もある。

print "--氏名--------------+-得点-+-平均との差--\n"
for i in 0..(score.length-1)		# 0 から(要素数-1)まで繰り返す
  printf("%-20s %5d   %5.1f\n", name[i], score[i], score[i]-average)
end

N..M は、2つの自然数 N から M (N<M)まですべての整数の集合を表す。

以上を組み合わせてプログラムは完成する。

score.rb

#!/usr/koeki/bin/ruby
# -*- coding: utf-8 -*-
# printfの%Xsでの幅を合わせるため
require './kprintf.rb'

score=[]
name =[]
sum = 0
while yomikomi = gets
  if /(\S+)\s+(\d+)/ =~ yomikomi
    name << $1
    score << $2.to_i
    sum += $2.to_i
  end
end
average = sum.to_f/score.length

i = 0
print "--氏名--------------+-得点-+-平均との差--\n"
while i < score.length
  printf("%-20s %5d   %5.1f\n", name[i], score[i], score[i]-average)
  i += 1
end

kprintf.rb

# kanji-aware printf for both Ruby1.8 or 1.9+
class String
  require 'kconv'
  if defined?("".force_encoding)
    def toeucbin()
      self.toeuc.force_encoding("binary")
    end
  else
    def toeucbin()
      self.toeuc
    end
  end
end

class IO
  def printf(*args)
    out = sprintf(*(args.collect{|x| x.is_a?(String) ? x.toeucbin : x }))
    print out.toutf8
  end
end

class Object
  def printf(*args)
    if args[0].is_a?(String)
      $stdout.printf(*args)
    else
      port = args.shift
      port.printf(*args)
    end
  end
end

上記プログラムで利用している kprintf.rb を同じディレクトリに保存してから実行してみよう。

./score.rb score.txt
--氏名--------------+-得点-+-平均との差--
山田太郎                50    -9.2
中町太郎                90    30.8
飯森花子                91    31.8
鶴岡一人                60     0.8
酒田三吉                52    -7.2
三川一二三              12   -47.2

本日の目次