roy > naoya > 基礎プログラミングII[月2] > (2)様々な繰り返し表現
前期には繰り返しの記法としてwhile-endを用いてきた。まずはこの記法について確認し、その後その他の繰り返し表現の方法について確認していく。
プログラムを実行すると、通常上から順番に1行ずつ実行される。これを逐次処理と呼んだが、このようなプログラムの流れを変えるものが制御構造であった。制御構造には前回行った「条件判断」と今回行う「繰り返し」があった。「繰り返し」は条件に応じて指定した処理を何度も繰り返し実施するというものであり、前期はwhile-endを取り上げた。
while-endの基本構造は以下の通りである。
while-endの基本構造
while 繰り返し条件 繰り返す処理 end
whileの横に書くのは x < 10 や y >= i のような繰り返しの継続条件である。この条件を満たす間はwhile-end間の処理を繰り返し実行する。具体例をあげながらもう一度確認してみよう(add10.rb)。
#!/usr/koeki/bin/ruby
sum = 0
goal = 10
i = 1
while i <= goal
  sum += i
  i += 1
end
printf ("sumは%dです\n",sum)
irsv{naoya}% ruby add10.rb[Return]
sumは55です。
このプログラムでは、3つの変数を使用しており、それぞれsum=0、goal=10、i=1という初期値を与えている。その後、while-endがあるが、whileの横には「i <= goal」とある。これが繰り返しを継続する条件である。具体的に繰り返す内容は、while-end間に書かれている「sum += i」と「i += 1」の2行である。
繰り返しを継続する条件である「i <= goal」は「iがgoal以下」という意味になる。iは初期値が1であり、goalは初期値が10である。while-end間を見ると、「i += 1」があることから、iの値は変化する(より厳密にはwhile-endの繰り返しを実施するたびに1ずつ増加する)ことになる。それに対してgoalは初期値が与えられているのみで、その後値は変化しない。つまり、iが1から2、3、4、・・・と増加していき、最終的に10になるまで繰り返し処理を継続せよということになる。
具体的に繰り返し継続される処理は「sum += i」と「i += 1」であった。これは「sumに現在のiの値を加算せよ」および「iに1加算せよ」ということになる。
while-end部の繰り返しがどのように行われるのかを表にして示してみよう。
繰り返し回数  | 
while i <= goal  | 
sum += i  | 
i += 1  | 
|---|---|---|---|
1回目  | 
iは1なので条件を満たす  | 
sumは1に  | 
iは2に  | 
2回目  | 
iは2なので条件を満たす  | 
sumは3に  | 
iは3に  | 
3回目  | 
iは3なので条件を満たす  | 
sumは6に  | 
iは4に  | 
4回目  | 
iは4なので条件を満たす  | 
sumは10に  | 
iは5に  | 
5回目  | 
iは5なので条件を満たす  | 
sumは15に  | 
iは6に  | 
6回目  | 
iは6なので条件を満たす  | 
sumは21に  | 
iは7に  | 
7回目  | 
iは7なので条件を満たす  | 
sumは27に  | 
iは8に  | 
8回目  | 
iは8なので条件を満たす  | 
sumは35に  | 
iは9に  | 
9回目  | 
iは9なので条件を満たす  | 
sumは44に  | 
iは10に  | 
10回目  | 
iは10なので条件を満たす  | 
sumは55に  | 
iは11に  | 
11回目  | 
iは11なので条件を満たさない(終了)  | 
実行されない  | 
実行されない  | 
繰り返しを行うごとにsumおよびiの値が増加していき、11回目の時点でiが11となり「while i <= goal」の繰り返し条件を満たさなくなるためこれで終了となる。
while-endを用いる場合、whileの横に繰り返し条件を具体的に記述するかわりに「while true」と記述することもできた。trueは常に条件を満たすという意味であり、while trueと書くことで永久に繰り返しを継続することができた。while trueを使用する場合は、while-end内に別途、繰り返しから抜けるための「break」を記述しておく必要があった。
以下は前期のレジスターのプログラムであり、購入した商品の単価(price)を連続して入力することで、購入した商品数(item)と合計金額(sum)を算出するものである。そして、ユーザがキーボードから「q」を入力した場合に繰り返しから抜けよという指示がされている。
priceにはユーザがキーボードから入力した値が代入される。「price = gets.chomp!」の行がそれにあたり、この行はwhile-end内に記述されている。つまり繰り返しを継続するかどうかは、whileの行では判断できず、while-end内の処理を実行して初めて決定する。このようなケースではとりあえず繰り返しは続けておき、繰り返し処理を行う中で終了するかどうかを判断するという、while trueが利用される。
checkstand.rb
#!/usr/koeki/bin/ruby
sum = 0
item = 0
while true
  print "金額を入力してください(終了はq): "
  price = gets.chomp!
    if price == "q" 
      then break
    end
  sum += price.to_i
  item += 1
  printf ("現時点の購入商品の個数は%d個、
  合計は %d 円です\n", item, sum)
end
printf ("ありがとうございます。お会計は %d 円になります\n", sum)
irsv{naoya}% ruby checkstand.rb[Return]
金額を入力してください(終了はq)
100[Return]
現時点の購入商品の個数は1個、合計は 100 円です
金額を入力してください(終了はq)
150[Return]
現時点の購入商品の個数は2個、合計は 250 円です
金額を入力してください(終了はq)
q[Return]
ありがとうございます。お会計は 250 円になります
このプログラムの強調部分(黄色の部分)が繰り返しから抜けるかどうかの判定部であるが、「if price == "q" 」となっている。右辺は"q"であるが、文字列の場合は""をつける。もしも数字で9999と入力したら終了としたければ「if price == 9999」となる。ただしこのプログラムに関しては「if price == "9999"」と書かなければならない。「price = gets.chomp!」の行で入力した値を取得してpriceに代入しているが、getsメソッドは文字列として取得する。つまり9999と入力したとしても整数の「きゅうせんきゅうひゃくきゅうじゅうきゅう」ではなく文字列の「きゅうきゅうきゅうきゅう」として扱われていることになる。整数に変換するためには.to_iメソッドを使用する必要があり、「price = gets.chomp!.to_i」としなければならない。このプログラムでは「sum += price.to_i」の行でpriceに.to_iをつけ整数に変換している。「price = gets.chomp!.to_i」としていないのは、ユーザが金額(整数)と終了のq(文字列)を入力する可能性があり、最初に全て整数に変換してしまうと都合が悪いからである(文字を.to_iメソッドで整数に変換すると0になる。)。このため「price = gets.chomp!.to_i」とするとqと入力しても0に変換されてpriceに代入されてしまい、price内の値がqである場合に繰り返しから抜けるという条件を満たすことがなくなってしまう。
以下のプログラムは何箇所がエラーがあり、正しく実行することができない。どこをどのように修正すればよいか答えよ。
#!/usr/koeki/bin/ruby
money = 0
while true
  print "金額を入力[終了はquit]:"
  money = gets.chomp!.to_i
  if money == quit
    break
  end
  sum += money
end
printf ("合計は%dです",sum)
制限時間は10分。出席点は2点。提出要領は下記の通り。
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:Mewによるメールの送り方はMewコマンドを参照
情報検索の授業では、繰り返しを行う際、主にwhileを用いてきた。ただし繰り返し処理にはwhile以外にもいくつかの方法がある。様々な方法を理解して自在に扱えるようにしよう。
timesは単純に一定回数繰り返す場合に用いる。以下のどちらの方法で記述しても構わない(times.rb)。
#!/usr/koeki/bin/ruby
4.times {
  print "Hello\n"
}
#!/usr/koeki/bin/ruby 4.times do print "Hello\n" end
irsv{学籍番号}%chmod +x times.rb
./times.rb
Hello
Hello
Hello
Hello
1から10までの合計を出すことを考えてみよう。while-endで記述した場合以下の通りとなる。
#!/usr/koeki/bin/ruby
goukei = 0
i = 1
while i <= 10
  goukei += i
  i += 1
end
printf ("goukeiの値は%dです\n",goukei)
このプログラムではiの初期値を1とし、繰り返しを行うごとにiの値を1ずつ増加しながらgoukeiに加えている。そしてiが10を超えたら終了になるため、結果的に1から10までの合計を出したことになる。
○から□まで1ずつ変化させながら処理を繰り返し行うという場合、while以外にuptoメソッド、downtoメソッドを使って表現することもできる。以下はuptoメソッドを用いて上記のプログラムを書き直したものとなる(sum-upto.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
1.upto(10) do |i| #from.upto(to)。1から10までiを1ずつ増加させる。
  goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
同様にdowntoメソッドを用いて書き直すと下記のようになる(sum-downto.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
10.downto(1) do |i| #from.downto(to)。10から1までiを1ずつ減少させる。
  goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
uptoメソッド、downtoメソッドの基本構造はそれぞれ以下の通りである。初期値と終了値をそれぞれfromとtoの位置に指定する。繰り返し処理を行う中でuptoメソッドはfromからtoまで変数の値を1ずつ増やしながら、downtoメソッドでは1ずつ減らしながら処理を継続する
uptoメソッドの基本構造
  初期値.upto(終了値) do |変数|
    繰り返す処理
  end
初期値と終了値には整数もしくは整数が代入された変数が使用可能
downtoメソッドの基本構造
  初期値.downto(終了値) do |変数|
    繰り返す処理
  end
初期値と終了値には整数もしくは整数が代入された変数が使用可能
なお、3.upto(1)のようにuptoメソッドにおいて初期値よりも終了値に小さな値を指定した場合や、1.downto(10)のようにdowntoメソッドにおいて初期値よりも終了値に大きな値を指定した場合は1回も処理は行われない。
uptoやdowntoは1ずつ増加、減少させながら繰り返し処理を行うためのメソッドである。では、10+20+30+、、、+100のように10ずつ増加する場合や、2+4+6+、、、+10のように2ずつ増加する場合はどうすればよいだろうか。これについてもまずはwhileでの表現方法を見てみよう。
#!/usr/koeki/bin/ruby
goukei = 0
i = 10
while i <= 100
  goukei += i
  i += 10
end
printf ("goukeiの値は%dです\n",goukei)
このようにiの初期値を10として、繰り返しを行う中でiの値を10ずつ増加させていけば書くことができる。なお、一定間隔で値を変える方法として、stepメソッドもある。stepメソッドの基本構造は下記の通りとなる。
stepメソッドの基本構造
   初期値.step(終了値, 増加値) do |変数|
    繰り返す処理
  end
初期値・終了値・増加値には整数もしくは整数が代入された変数が使用可能
stepメソッドでは3つの値を指定する。初期値と終了値はuptoメソッド、downtoメソッドと同様であるが、加えて増加値を指定する。これにより10ずつ増加させるということが可能になる。
増加値は省略可能であるが、この場合は増加値=1とみなされる。10から100まで100ずつ増加させて加算するプログラムを書くと以下のようになる(sum-step.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
10.step(100, 10) do |i|
  goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
増加値には負の値を入れることもできる。10から初めて100まで10ずつ増加させながら足し算をするということは、100から初めて10まで10ずつ減らしながら足し算をすることと同義である。上記のプログラムの開始値、終了値、増加値をそれぞれ100、10、-10に変更しても同じ結果となる。
1ずつ増やしながら処理を繰り返すには、forと整数範囲を用いた表現も可能である。整数範囲には1..10のように初期値と終了値を指定する。そして初期値から終了値まで1ずつ増やしながら変数に代入し、繰り返し処理を行う。
for-endの用法[1]−整数範囲の指定
  for 変数 in 整数範囲
    繰り返す処理
  end
整数範囲は1..10のように初期値..終了値を記載する。初期値から終了値まで変数に順番に代入しながらfor−end間の処理を繰り返し行う。
これで1から10までの合計を記述すると以下のようになる(sum-for.rb)。
#!/usr/koeki/bin/ruby
goukei = 0
for i in 1..10 #iに1から10まで順次代入する
 goukei += i
end
printf ("goukeiの値は%dです\n",goukei)
整数範囲の代わりに配列を指定すると、その配列に代入された値を順番に取り出して使用することができる。
for-endの用法[2]−配列の指定
  for 変数 in 配列
    繰り返す処理
  end
配列内の0番目の要素から順番に変数に代入しながらfor−end間の処理を繰り返し行う。配列内の全ての要素を読み出したら終了となる。
これで配列から順番に値を取り出して表示すると以下のようになる(array-for.rb)。
#!/usr/koeki/bin/ruby
test = [80, 75, 90, 88, 60]
sum = 0
for i in test #iにtestの0番目の要素から順に代入する
 sum += i
end
printf ("テストの合計は%d点です\n",sum)
以下のうちいずれかを選んで解答する。プログラムはwhile-end以外の繰り返し表現を用いて記述すること。while-endを用いた場合や繰り返し表現を用いなかった場合は、配点を1点マイナスとする(例えば、9点満点の問題は8点満点で採点)。
問題1(7点満点):指定した任意の自然数(=正の整数)からはじめて、100までのその自然数の倍数を全て足した値を求めるaddsum.rbを作成せよ
問題2(9点満点):1から100までの素数の和を求めるprime.rbを作成せよ。ここで、素数とは1とその数以外に約数がない正の整数を指し、結果は例えば素数が1,2,3,5である場合「1+2+3+5=11」というように式形式で表示されるようにせよ
Tips:emacsでの日本語入力のオンオフはCtrl-oです
Tips:ktermでのプログラムの実行結果をメールに貼り付けるには、コピーしたい箇所をマウスで選択し、emacs(Mew)上でマウスの真ん中ボタンをクリックする
Tips:Mewによるメールの送り方はMewコマンドを参照