ループ(繰り返し)

教科書 Lesson 4 続き

これ以降は、教科書の Lesson 4 の続きを進めてください。

教科書に沿ってそのままやってもらいたいところですが、節ごとに簡単な課題を用意してみました。

4.4 for 文

p.75〜p.78までを試しながら進め、それが済めば次の例題をやってください。

例題1. 1から10までの合計を得る

for 文を使ったループを使って、1 + 2 + … + 10 を求めるには、以下のようにします。

total = 0
for i in range(10):
    total = total + (i +1)
    print(total)
print("total = ", total)

以下の点に注意してください。

課題1. 上の例題を「1から入力した数まで」に修正する

例題は 1〜10まで、でしたが、これを 1 から 入力した数までの合計を求めるように修正してください。

ループ制御変数の名前が i や j なのは何故か
for に続いてループカウンタとして使われている変数名が「 i 」なのは何を意味しているのだろう?と疑問に思えるかもしれません。参考に「何故その変数名は「 i 」なのか 」に少しまとめてみました。

4.5 while 文

p.79〜p.81までを読み進め、それが済めば次の例題をやってください。

例題2. 入力した数の合計を得る

以下に while 文を使って、繰り返して入力した数の合計を求めるプログラムを示します。

total = 0
num = int(input("num = "))  # 一つ目の数の入力
while num > 0:
    total = total + num
    print(total)
    num = int(input("num = "))  # 二つ目以降の数の入力
print("total = ", total)

このプログラムは「0(ゼロ)」を入力すると、それ以降はループを継続せず、total 変数を print します。以下に実行結果を示します。

yasuda@Slack 08 % python3 while.py
num = 4
4
num = 2
6
num = 6
12
num = 0
total =  12
yasuda@Slack 08 % 

以下の点に注意してください。

課題2. 上の例題を「合計ではなく平均を得る」ように修正する

例題は合計を出していましたが、これを平均を求めるように修正してください。

ところで平均を求めるためには、合計と要素の数が必要です。つまり上のプログラムに「要素数(ループ回数)を数える」機能を追加し、最後の出力を「合計」ではなく「平均」に変更するのです。

4.6 文のネスト(というかループのネスト)

p.82〜p.85までを試しながら進めてください。この節は例題がいくつかありますから、それをやれば十分でしょう。教科書で扱っている例題は以下の二つです。

二つ目の課題の記号の変更

if との組み合わせの課題は、* と _ でやるより、■ と □ でやる方が、見た目カッコ良いかもしれません。

yasuda@Slack 08 % python3 nest.py
■ □ ■ □ ■ 
□ ■ □ ■ □ 
■ □ ■ □ ■ 
□ ■ □ ■ □ 
■ □ ■ □ ■ 
yasuda@Slack 08 %  

4.7 処理の流れの変更(というか break と continue)

p.86〜p.89までを読み進め、それが済めば次の例題をやってください。

例題3. 約数を数える

以下に入力した数の約数と、その個数を表示するプログラムを示します。動きが追えるでしょうか。(6 の約数は 1, 2, 3, 6)

number = int(input())
count = 0
for i in range(1, number + 1):
    print("check", i, end="") # 改行なし
    if number % i == 0:
        print(" は約数", end="") # 約数のマークを追加(改行なし)
        count += 1
    print() # 改行を追加
print("約数の個数は", count)

実行結果は以下のようになります。

yasuda@Cecil 08 % python3 divisor.py
6
check 1 は約数
check 2 は約数
check 3 は約数
check 4
check 5
check 6 は約数
約数の個数は 4
yasuda@Cecil 08 % 

課題3. 上の例題を「素数か否かを判定」ように修正する

例題は約数を出していましたが、そこに修正を加えて入力した数が素数か否かを判定するように修正してください。以下のような実行結果となるよう修正してください。

yasuda@Cecil 08 % python3 prime.py
6              <<< 6を入力した
check 2 は約数
check 3 は約数
check 4
check 5
6 は素数ではない
yasuda@Cecil 08 % python3 prime.py
7              <<< 7を入力した
check 2
check 3
check 4
check 5
check 6
7 は素数
yasuda@Cecil 08 % 

ところで素数か否かを判定するためには、2からその数より一つ小さな数まで、片っ端から割ってみて割り切れることが一度も無いことを確認する「試し割り」と呼ばれる手法で行うのが簡単です。

つまり上の例題プログラムに対して、以下のような変更を施せば良いはずです。

上のアイディアで修正できたら、以下の検討をしてください

つまり「試し割り」による素数判定ですが、例えば 100 を入力した場合、最初の 2 で割った余りがゼロであった時点で素数でないことが確定します。しかし上の例題のアルゴリズムをそのまま使うと、残り 98 回、延々と試し割りを続けることになります。これは break によって処理を中断すべき場面です。

そのようにして無駄のないプログラムとして完成させてください。

Flag というアイディア
最後の課題は、例題を元にすると count という名前の変数を使ったまま「完成」となるでしょう。しかし break によって処理を中断する形にした場合、実質的に count 変数は数を数えるようなことはなく、ループを抜けてきた時には 0 か 1 のどちらか、となっているでしょう。これはもう「count」ではなく、事象が起きたか起きなかったか、を示す名前に変えるべきです。
プログラミングの定石(よくあるパターン)としては、これは「フラグ」と呼ばれる考え方・手法です。処理の最初に「旗」を寝かしておき、(繰り返しを含めた)処理の途中で一度でも事象が起きたら「旗を立てる」ことでそのことを記録する、というものです。変数名を flag に変えて、値も 0 ではなく False を入れておき、割り切れたら True にする、などとすれば良いでしょう。
(初期値が True で、割り切れたら False にするほうが直感に合う人はそうすれば良いです。)

Lesson 4 のまとめ

さて、これで教科書の p.90 「4.8 レッスンのまとめ」まで来ました。そこに書かれていることが理解出来ますか?

今回は課題をたくさんやったので、p.91 の「練習」はやらなくて良いでしょう。ただ、p.90 の「まとめ」が納得いかない、という人は p.91 の「練習」をやるのが良いと思います。

【おまけ】break の事例

例題2. 入力した数の合計を得る」で、「二箇所に同じ処理がある」のが不満(気に入らない)という人向けに、break を使ってそれを改善したプログラムを載せておきます。参考まで。input の処理が一箇所になっているのが分かるでしょう。break の典型的な使い方の一つと思います。

total = 0
while True:
    num = int(input("num = "))  
    if num == 0: # 入力がゼロならループを脱出
        break
    total = total + num
    print(total)
print("total = ", total)