コンピュータ演習II 第06回 繰り返し処理(for 文)¶
この回では、同じような処理を何度も繰り返すための for 文 を学びます。これまでは「上から順に 1 行ずつ」実行するコードを書いてきましたが、似た処理を何度も並べるのは大変です。for 文を使うと、繰り返しを短く正確に書けます。 前回学んだ リスト と組み合わせると、for 文はとても強力になります。for 文は、この先の回(2 重ループ、整列、探索など)でずっと使い続ける大事な道具です。 これまでと同じように、Colab で実際にコードを書いて実行しながら読み進めてください。
1. for 文の基本¶
1.1 同じ処理の繰り返し¶
たとえば、掛け算の 5 の段(5 × 1 から 5 × 9 まで)を計算して表示することを考えます。これまでのやり方だと、同じような行を何度も並べることになります。
a = 5 * 1
print("5 ×", 1, "=", a)
a = 5 * 2
print("5 ×", 2, "=", a)
a = 5 * 3
print("5 ×", 3, "=", a)
# 以下、5 × 9 まで続く...
5 × 1 = 5 5 × 2 = 10 5 × 3 = 15
このコードをよく見ると、1、2、3... と 連番の数字だけが 1 ずつ増えている ことに気づきます。
この連番を変数i で表すと、繰り返しの中でおかなわれている実質的な処理は 2 行にまとめられます。
i = 3 # この i を 1、2、3... と変えれば、各段の計算ができる
a = 5 * i
print("5 ×", i, "=", a)
5 × 3 = 15
つまり、i を 1 から 9 まで 1 ずつ変化させられれば、すべての計算結果を一括で得られそうです。これを実現するのが for 文 です。実際に書くと、次のようになります。
for i in range(1, 10):
a = 5 * i
print("5 ×", i, "=", a)
5 × 1 = 5 5 × 2 = 10 5 × 3 = 15 5 × 4 = 20 5 × 5 = 25 5 × 6 = 30 5 × 7 = 35 5 × 8 = 40 5 × 9 = 45
このコードをフローチャートで表すと、次のようになります(これ以降も、コード例の下に対応するフローチャートを載せます。図の読み方は4 章でくわしく説明します)。
たった 3 行で、5 × 1 から 5 × 9 までをすべて表示できました。ポイントは 1 行目の
for i in range(1, 10):
の部分です。これは
変数
iを1から10 - 1 = 9まで 1 ずつ増やしながら、下のインデントされた部分を繰り返し実行する
という意味になります。
練習: 7 の段を表示してください¶
for 文を使って、7 × 1 から 7 × 9 までの計算結果を表示してください。上の 5 の段のコードを参考にしてください。
# 7 の段を for 文で表示してください
1.2 range の意味¶
for i in range(1, 10): の range(1, 10) が、繰り返しの範囲を決めています。一般に書くと
range(開始, 終了)→ 開始 から 終了 の 1 つ手前(終了- 1)まで、1 ずつ
です。終了の値そのものは含まれない(1 つ手前で止まる)のが、まちがえやすいところです。たとえば range(1, 10) は 1, 2, 3, ..., 9 で、10 は含みません。
次のコードで、i がどのように変化するか確かめてください。
for i in range(1, 5):
print(i)
1 2 3 4
1、2、3、4 の 4 つが順に表示されます(5 は含まれません)。
for 文で使う変数の名前は、i でなくてもかまいません。次のように k でも同じように動きます。
for k in range(1, 5):
print(k)
1 2 3 4
特に理由はありませんが、慣例として i がよく使われます。for 文を 2 つ、3 つと使うときは i、j、k の順で使うことが多いです。
なお、すでに別の用途で使っている変数を for 文の変数に使うと、その値が上書きされて消えてしまうので注意してください。初学者のうちは、i、j、k は for 文専用 と決めておくと安全です。
練習: i の2乗(平方数)をi = 1 から 9 まで表示してください¶
for 文を使って、1 × 1, 2 × 2, 9 × 9 までの計算結果を表示してください。
# 平方数を for 文で表示してください
1.3 インデントによるfor ブロック(繰り返す対象)の指定¶
for 文で繰り返されるのは、for の行の下の インデント(字下げ)された部分 です。どこまでが繰り返しの範囲なのかは、このインデントで決まります。
if 文と同じですね。
次の 2 つのコードを見くらべてください。print の位置(インデントの内か外か)だけが違います。
# print がインデントの「中」にある
for i in range(1, 5):
a = 5 * i
print("5 ×", i, "=", a)
5 × 1 = 5 5 × 2 = 10 5 × 3 = 15 5 × 4 = 20
print がインデントの「中」にあるとき(出力は繰り返しのたびに行われる)
# print がインデントの「外」にある
for i in range(1, 5):
a = 5 * i
print("5 ×", i, "=", a)
5 × 4 = 20
print がインデントの「外」にあるとき(出力はループが終わってから 1 回だけ)
下のコードを実行すると、いちばん最後の計算結果(5 × 4 = 20)しか表示されません。print がインデントの外にあるため、繰り返しには含まれず、for 文がすべて終わったあとに 1 回だけ実行されるからです。
このように、どこまでを繰り返したいのか をインデントで正しく示すことがとても大事です。思ったとおりに動かないときは、まずインデントを確認してください。
1.4 任意の回数の繰り返し、if との組み合わせ¶
range(0, n) と書くと、0 から n - 1 まで、つまり ちょうど n 回 繰り返します。「同じ処理を n 回繰り返したい」というときによく使う形です。
for i in range(0, 3):
print("こんにちは")
こんにちは こんにちは こんにちは
「こんにちは」 が 3 回表示されます。
for 文の中に、第03回・第04回で学んだ if 文 を入れることもできます。次は、1 から 9 までのうち 偶数のときだけ 5 の段を計算するコードです。
for i in range(1, 10):
if i % 2 == 0: # i が偶数(2 で割った余りが 0)なら
a = 5 * i
print("5 ×", i, "=", a)
5 × 2 = 10 5 × 4 = 20 5 × 6 = 30 5 × 8 = 40
for 文の中に if 文を入れるときは、if 文のためのインデントがさらに必要 です。for の中が 1 段、その中の if の中がもう 1 段、と階段状に下がっていきます。インデントの段数をまちがえると、思ったとおりに動かないので注意してください。
練習: 3 の倍数だけ表示してください¶
for 文と if 文を組み合わせて、1 から 20 までの数のうち、3 の倍数だけ を表示してください(3 の倍数は、3 で割った余りが 0 の数です)。
# 1 から 20 までのうち、3 の倍数だけを表示してください
2. リストとの併用¶
2.1 リストの全要素を順に処理する¶
for 文は、前回学んだ リスト と組み合わせると本領を発揮します。たとえば、3 人分の年齢が入ったリストの中身を 1 つずつ表示することを考えます。これまでのやり方だと、次のようになります。
age_list = [20, 13, 24]
print(0, "人目の年齢:", age_list[0])
print(1, "人目の年齢:", age_list[1])
print(2, "人目の年齢:", age_list[2])
0 人目の年齢: 20 1 人目の年齢: 13 2 人目の年齢: 24
ここでもインデックス(0、1、2)が連番で増えています。この連番を for 文の変数i にすれば、次のように書けます。
age_list = [20, 13, 24]
for i in range(0, 3):
print(i, "人目の年齢:", age_list[i])
0 人目の年齢: 20 1 人目の年齢: 13 2 人目の年齢: 24
i が 0、1、2 と変わり、そのつど age_list[i] にアクセスするので、リストの要素を順に表示できます。
2.2 len を使って「長さが変わっても動く」コードにする¶
上のコードには、まだよくない点があります。range(0, 3) の 3(人数)を直接書いてしまっているため、リストの要素数が変わると正しく動きません。たとえば人数が 5 人に増えると、3 人分しか表示されません。
age_list = [20, 13, 24, 32, 19] # 5 人に増えた
for i in range(0, 3): # でも 3 のまま
print(i, "人目の年齢:", age_list[i])
0 人目の年齢: 20 1 人目の年齢: 13 2 人目の年齢: 24
前回学んだ len を使えば、リストの長さを自動で求められます。range(0, len(age_list)) と書けば、リストの長さがいくつであっても 全要素を処理できます。
age_list = [20, 13, 24, 32, 19]
for i in range(0, len(age_list)): # 長さが変わっても全部まわる
print(i, "人目の年齢:", age_list[i])
0 人目の年齢: 20 1 人目の年齢: 13 2 人目の年齢: 24 3 人目の年齢: 32 4 人目の年齢: 19
len(age_list) は要素数(ここでは 5)なので、range(0, 5) と同じになり、i は 0 から 4 まで動きます。これでリストの長さに左右されない、よいコードになりました。リストを for 文でまわすときは range(0, len(リスト)) が基本の形だと覚えておきましょう。
練習: リストの全要素を表示してください¶
次のリスト prices について、range(0, len(prices)) を使って、全要素を 0 番目: 120 のように 1 つずつ表示してください。len を使っているので、prices に要素を増やしても、コードを変えずに動くことを確かめてください。
prices = [120, 80, 250, 300]
# range(0, len(prices)) を使って、全要素を「0 番目: 120」のように表示してください
2.3 繰り返しでリストに要素を追加する(append)¶
前回学んだ append を for 文の中で使うと、要素を 1 つずつ増やしながらリストを組み立てられます。たとえば、第03回で学んだ乱数を使って、0 から 10 までの整数乱数を 5 個ためたリストを作ってみます。
import random
values = [] # 空のリストから始める
for i in range(0, 5):
r = random.randint(0, 10) # 0 から 10 までの整数乱数
values.append(r) # リストの後ろに追加
print(values)
[1, 5, 10, 5, 8]
空のリストから始めて、繰り返しのたびに 1 つずつ append するので、5 個の要素を持つリストができあがります。range の数を変えれば、ためる個数も自由に変えられます。
(なお、append はリストを後から伸ばす Python の便利な機能です。Flowchart Maker でも、変数 / 値ブロックの変数欄を空にして numbers.append(i) のように書けば、同じ処理を表せます。)
練習: append でリストを作ってください¶
空のリスト numbers = [] から始めて、for 文の中で append を使い、1 から 10 までの整数を 1 つずつ追加してください。最後に numbers を表示すると [1, 2, 3, ..., 10] になります。
numbers = []
# for 文と append で、1 から 10 までを numbers に追加して表示してください
3. for 文でよく使うパターン¶
ここからは、for 文とリストを使った代表的なパターンを紹介します。どれも「変数を 1 つ用意しておき、繰り返しのたびに少しずつ更新する」という共通の形をしています。まずは、その「更新」の仕組みから見ていきます。
3.1 変数を更新する(破壊的代入)¶
総和やカウントでは、s = s + a[i] や count = count + 1 のように、同じ変数を = の左と右の両方に書く ことがよくあります。数学の等式として読むと「s と s + 1 が等しい」となって変ですが、プログラムの = は 「等しい」ではなく「右側を計算して、その結果を左側の変数に入れる(代入)」 という意味でした(第03回で == と = の違いを学びました)。
そのため s = s + 1 は、次の意味になります。
いまの
sの値に1を足し、その結果を 新しいsの値にする(もとの値は上書きされて消える)
右側が先に計算され、そのとき s はまだ古い値です。計算結果が s に入ると、古い値は捨てられます。このように、変数のもとの値を新しい値で置き換える代入を 破壊的代入 と呼びます。
s = 0
print(s) # 0
s = s + 5 # いまの s(0) に 5 を足した 5 が、新しい s になる
print(s) # 5
s = s + 3 # いまの s(5) に 3 を足した 8 が、新しい s になる
print(s) # 8
0 5 8
このように、s = s + ... を繰り返すと、s に値がどんどんたまっていきます。これが、次に学ぶ総和やカウントの土台です。カウントで使う count = count + 1 も同じ考え方で、「いまの count に 1 を足して、新しい count にする」、つまり count を 1 増やす という意味になります。
3.2 総和(と平均)¶
リストの全要素の合計(総和)を求めます。まず合計用の変数s を 0 にしておき、繰り返しのたびに要素を 1 つずつ足していきます。
a = [10, 30, 40]
s = 0 # 合計を入れる変数。最初は 0
for i in range(0, len(a)):
s = s + a[i] # s に a[i] を足していく
print("合計:", s)
合計: 80
s = s + a[i] は「いまの s に a[i] を足して、その結果を新しい s にする」という意味です。繰り返すうちに、s に全要素の合計がたまっていきます。
平均は、合計をリストの長さで割れば求められます。
a = [10, 30, 40]
s = 0
for i in range(0, len(a)):
s = s + a[i]
print("平均:", s / len(a))
平均: 26.666666666666668
3.3 条件に合う要素を数える(カウント)¶
次は、リストの中に条件に合う要素がいくつあるかを数えます。数える用の変数count を 0 にしておき、条件に合うたびに 1 ずつ増やします。下の例では、80 以上の要素の個数を数えます。
scores = [90, 98, 85, 72, 63]
count = 0 # 数えるための変数。最初は 0
for i in range(0, len(scores)):
if scores[i] >= 80: # 80 以上なら
count = count + 1 # 1 増やす
print("80 以上の個数:", count)
80 以上の個数: 3
for 文の中に if 文を入れ、条件に合ったときだけ count を増やすのがポイントです。「合計したい」なら s = s + ...、「数えたい」なら count = count + 1、と使い分けます。
3.4 最大値を見つける¶
複数の数値を格納したリストtarget の中の最大値を求めます。次のような手順を考えます。
まず変数
maxvalueに先頭の要素target[0]を入れておく。次にtarget[1]、target[2]... と順に見ていき、maxvalueより大きい要素が見つかるたびに、maxvalueをその値に更新する。
こうすると、maxvalue には「ここまでで見た中でいちばん大きい値(暫定的な最大値)」が入り続け、最後まで見終わると本当の最大値になります。
target = [2, 3, 6, 4, 1, 8, 9]
maxvalue = target[0] # まず先頭を暫定の最大値にする
for i in range(1, len(target)): # 1 番目から順に比べる
if target[i] > maxvalue: # maxvalue より大きい要素が見つかったら
maxvalue = target[i] # maxvalue を更新する
print("最大値:", maxvalue)
最大値: 9
ここでは range(1, len(target)) と、1 から始めています。maxvalue に target[0] をすでに入れたので、比べるのは target[1] からでよいからです。
同じ考え方で、if target[i] > maxvalue を if target[i] < maxvalue に変えれば最小値を求められます。考えてみてください。
(なお Python には合計や最大値を求める sum、max といった便利な命令もありますが、この回では 自分で for 文を使って求める練習 をします。仕組みを自分で組み立てられることが大事です。)
練習: 合計と最大値を求めてください¶
次のリスト data について、for 文を使って 合計 と 最大値 を求め、それぞれ表示してください。最大値は max を使わず、3 章で学んだやり方(先頭を暫定の最大値にして更新する)で求めてください。
data = [12, 5, 28, 9, 17]
# for 文で合計を求めて表示してください
# for 文で最大値を求めて表示してください。max は使わない
4. フローチャートで for 文を組む¶
ここまで Python で書いてきた繰り返しを、フローチャートでも表せます。Flowchart Maker では、繰り返しを for 繰り返しブロック(ひし形)で表します。
4.1 for ブロックの書き方¶
for 繰り返しブロックのひし形には、Python と同じ for i in range(0, 5): をそのまま書きます(変数と反復対象を続けて書く形です)。ひし形から出る2 つの矢印は、次あり(繰り返す値がまだある)と 次なし(繰り返しが終わった)の2 通りに分かれます。次あり の先に繰り返す処理(ループの本体)を置き、本体の終わりから 戻る でひし形へ戻ります。次なし の先が、繰り返しを抜けたあとの流れです。
上の図は、i を 0 から 4 まで動かしながら i を出力する、もっとも単純な例です。range(0, 5) の終わりの値(5)を含まないのは Python と同じで、フローチャートでも同じ範囲になります。
4.2 リストの全要素を繰り返し処理する¶
リストを繰り返し処理するときも考え方は同じです。numbers の全要素を見るには、for ブロックの反復対象に range(0, len(numbers)) と書き、ブロックの中で numbers[i] を使います。Python と同じ len がそのまま使えます。
Python の for i in range(0, len(numbers)): と、まったく同じ処理を表しています。
4.3 総和を求める¶
総和もフローチャートで作れます。
リストnumbers の合計を for ブロックで求めることを考えます。
ループに入る前に total = 0 としておき、次あり の先で total = total + numbers[i] を繰り返し、次なし に抜けたあとで total を出力すれば合計が得られます。
Python で書いた総和のコードと、同じ流れになっていることを確かめてください。最大値を求めるときも、maxvalue = numbers[0] から始めて、ループの中で if と更新を行う、という同じ形で作れます。
5. 演習: 学籍番号の各桁を for 文で処理する¶
最後に、この回で学んだことを、自分の 学籍番号後半 5 桁 を使って練習します。次のように、後半 5 桁の数字を1 つずつ要素にしたリストdigits を用意します(digits を作る式の仕組みは、いまは気にしなくてかまいません。5 つの数字が順に要素として並ぶ、とだけ分かれば十分です)。
sid = 61250 # ← 自分の学籍番号後半 5 桁に書き換えてください
digits = [sid // 10000 % 10, sid // 1000 % 10, sid // 100 % 10, sid // 10 % 10, sid % 10]
print(digits) # 61250 なら [6, 1, 2, 5, 0] と表示される
[6, 1, 2, 5, 0]
この digits を for 文でまわして、digits の全要素の 合計 を求めて表示するプログラムを書いてください。
sid をいろいろ変えて、結果が変わることも確かめましょう。
それぞれ別のセルに書いて、実行して確かめてください。
sid = 61250
digits = [sid // 10000 % 10, sid // 1000 % 10, sid // 100 % 10, sid // 10 % 10, sid % 10]
# digits の総和計算を for 文を使って書いてください
まとめ¶
この回では、同じような処理を繰り返す for 文 を学びました。
- for 文の基本:
for i in range(開始, 終了):で、変数iを 開始 から 終了- 1まで 1 ずつ増やしながら、インデントの中を繰り返す。終了の値は含まれない。 - インデント:繰り返す範囲はインデントで決まる。for の中に if を入れるときは、さらにインデントを下げる。
- リストとの併用:
for i in range(0, len(リスト)):で全要素を順に処理する。lenを使うと、長さが変わっても動く。 - よく使うパターン:変数を用意して少しずつ更新する。総和(
s = s + a[i])、カウント(count = count + 1)、最大値(暫定値を更新)。
for 文は、次回以降の繰り返し処理や、整列・探索のアルゴリズムで繰り返し使う、もっとも大事な道具の 1 つです。