コンピュータ演習II 第06回 繰り返し処理(for 文)¶

この回では、同じような処理を何度も繰り返すための for 文 を学びます。これまでは「上から順に 1 行ずつ」実行するコードを書いてきましたが、似た処理を何度も並べるのは大変です。for 文を使うと、繰り返しを短く正確に書けます。 前回学んだ リスト と組み合わせると、for 文はとても強力になります。for 文は、この先の回(2 重ループ、整列、探索など)でずっと使い続ける大事な道具です。 これまでと同じように、Colab で実際にコードを書いて実行しながら読み進めてください。

1. for 文の基本¶

1.1 同じ処理の繰り返し¶

たとえば、掛け算の 5 の段(5 × 1 から 5 × 9 まで)を計算して表示することを考えます。これまでのやり方だと、同じような行を何度も並べることになります。

In [2]:
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 行にまとめられます。

In [3]:
i = 3                    # この i を 1、2、3... と変えれば、各段の計算ができる
a = 5 * i
print("5 ×", i, "=", a)
5 × 3 = 15

つまり、i を 1 から 9 まで 1 ずつ変化させられれば、すべての計算結果を一括で得られそうです。これを実現するのが for 文 です。実際に書くと、次のようになります。

In [4]:
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 章でくわしく説明します)。

No description has been provided for this image

たった 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 の段のコードを参考にしてください。

In [7]:
# 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 がどのように変化するか確かめてください。

In [5]:
for i in range(1, 5):
    print(i)
1
2
3
4
No description has been provided for this image

1、2、3、4 の 4 つが順に表示されます(5 は含まれません)。 for 文で使う変数の名前は、i でなくてもかまいません。次のように k でも同じように動きます。

In [6]:
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 までの計算結果を表示してください。

In [27]:
# 平方数を for 文で表示してください

1.3 インデントによるfor ブロック(繰り返す対象)の指定¶

for 文で繰り返されるのは、for の行の下の インデント(字下げ)された部分 です。どこまでが繰り返しの範囲なのかは、このインデントで決まります。 if 文と同じですね。 次の 2 つのコードを見くらべてください。print の位置(インデントの内か外か)だけが違います。

In [25]:
# 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 がインデントの「中」にあるとき(出力は繰り返しのたびに行われる)

No description has been provided for this image
In [ ]:
# print がインデントの「外」にある
for i in range(1, 5):
    a = 5 * i
    
print("5 ×", i, "=", a)
5 × 4 = 20

print がインデントの「外」にあるとき(出力はループが終わってから 1 回だけ)

No description has been provided for this image

下のコードを実行すると、いちばん最後の計算結果(5 × 4 = 20)しか表示されません。print がインデントの外にあるため、繰り返しには含まれず、for 文がすべて終わったあとに 1 回だけ実行されるからです。 このように、どこまでを繰り返したいのか をインデントで正しく示すことがとても大事です。思ったとおりに動かないときは、まずインデントを確認してください。

1.4 任意の回数の繰り返し、if との組み合わせ¶

range(0, n) と書くと、0 から n - 1 まで、つまり ちょうど n 回 繰り返します。「同じ処理を n 回繰り返したい」というときによく使う形です。

In [10]:
for i in range(0, 3):
    print("こんにちは")
こんにちは
こんにちは
こんにちは
No description has been provided for this image

「こんにちは」 が 3 回表示されます。 for 文の中に、第03回・第04回で学んだ if 文 を入れることもできます。次は、1 から 9 までのうち 偶数のときだけ 5 の段を計算するコードです。

In [11]:
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
No description has been provided for this image

for 文の中に if 文を入れるときは、if 文のためのインデントがさらに必要 です。for の中が 1 段、その中の if の中がもう 1 段、と階段状に下がっていきます。インデントの段数をまちがえると、思ったとおりに動かないので注意してください。

練習: 3 の倍数だけ表示してください¶

for 文と if 文を組み合わせて、1 から 20 までの数のうち、3 の倍数だけ を表示してください(3 の倍数は、3 で割った余りが 0 の数です)。

In [12]:
# 1 から 20 までのうち、3 の倍数だけを表示してください

2. リストとの併用¶

2.1 リストの全要素を順に処理する¶

for 文は、前回学んだ リスト と組み合わせると本領を発揮します。たとえば、3 人分の年齢が入ったリストの中身を 1 つずつ表示することを考えます。これまでのやり方だと、次のようになります。

In [13]:
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 にすれば、次のように書けます。

In [14]:
age_list = [20, 13, 24]
for i in range(0, 3):
    print(i, "人目の年齢:", age_list[i])
0 人目の年齢: 20
1 人目の年齢: 13
2 人目の年齢: 24
No description has been provided for this image

i が 0、1、2 と変わり、そのつど age_list[i] にアクセスするので、リストの要素を順に表示できます。

2.2 len を使って「長さが変わっても動く」コードにする¶

上のコードには、まだよくない点があります。range(0, 3) の 3(人数)を直接書いてしまっているため、リストの要素数が変わると正しく動きません。たとえば人数が 5 人に増えると、3 人分しか表示されません。

In [15]:
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)) と書けば、リストの長さがいくつであっても 全要素を処理できます。

In [16]:
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
No description has been provided for this image

len(age_list) は要素数(ここでは 5)なので、range(0, 5) と同じになり、i は 0 から 4 まで動きます。これでリストの長さに左右されない、よいコードになりました。リストを for 文でまわすときは range(0, len(リスト)) が基本の形だと覚えておきましょう。

練習: リストの全要素を表示してください¶

次のリスト prices について、range(0, len(prices)) を使って、全要素を 0 番目: 120 のように 1 つずつ表示してください。len を使っているので、prices に要素を増やしても、コードを変えずに動くことを確かめてください。

In [ ]:
prices = [120, 80, 250, 300]

# range(0, len(prices)) を使って、全要素を「0 番目: 120」のように表示してください

2.3 繰り返しでリストに要素を追加する(append)¶

前回学んだ append を for 文の中で使うと、要素を 1 つずつ増やしながらリストを組み立てられます。たとえば、第03回で学んだ乱数を使って、0 から 10 までの整数乱数を 5 個ためたリストを作ってみます。

In [17]:
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]
No description has been provided for this image

空のリストから始めて、繰り返しのたびに 1 つずつ append するので、5 個の要素を持つリストができあがります。range の数を変えれば、ためる個数も自由に変えられます。 (なお、append はリストを後から伸ばす Python の便利な機能です。Flowchart Maker でも、変数 / 値ブロックの変数欄を空にして numbers.append(i) のように書けば、同じ処理を表せます。)

練習: append でリストを作ってください¶

空のリスト numbers = [] から始めて、for 文の中で append を使い、1 から 10 までの整数を 1 つずつ追加してください。最後に numbers を表示すると [1, 2, 3, ..., 10] になります。

In [ ]:
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 に入ると、古い値は捨てられます。このように、変数のもとの値を新しい値で置き換える代入を 破壊的代入 と呼びます。

In [18]:
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
No description has been provided for this image

このように、s = s + ... を繰り返すと、s に値がどんどんたまっていきます。これが、次に学ぶ総和やカウントの土台です。カウントで使う count = count + 1 も同じ考え方で、「いまの count に 1 を足して、新しい count にする」、つまり count を 1 増やす という意味になります。

3.2 総和(と平均)¶

リストの全要素の合計(総和)を求めます。まず合計用の変数s を 0 にしておき、繰り返しのたびに要素を 1 つずつ足していきます。

In [19]:
a = [10, 30, 40]
s = 0                              # 合計を入れる変数。最初は 0
for i in range(0, len(a)):
    s = s + a[i]                   # s に a[i] を足していく
    
print("合計:", s)
合計: 80
No description has been provided for this image

s = s + a[i] は「いまの s に a[i] を足して、その結果を新しい s にする」という意味です。繰り返すうちに、s に全要素の合計がたまっていきます。 平均は、合計をリストの長さで割れば求められます。

In [20]:
a = [10, 30, 40]
s = 0
for i in range(0, len(a)):
    s = s + a[i]
    
print("平均:", s / len(a))
平均: 26.666666666666668
No description has been provided for this image

3.3 条件に合う要素を数える(カウント)¶

次は、リストの中に条件に合う要素がいくつあるかを数えます。数える用の変数count を 0 にしておき、条件に合うたびに 1 ずつ増やします。下の例では、80 以上の要素の個数を数えます。

In [21]:
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
No description has been provided for this image

for 文の中に if 文を入れ、条件に合ったときだけ count を増やすのがポイントです。「合計したい」なら s = s + ...、「数えたい」なら count = count + 1、と使い分けます。

3.4 最大値を見つける¶

複数の数値を格納したリストtarget の中の最大値を求めます。次のような手順を考えます。

まず変数maxvalue に先頭の要素 target[0] を入れておく。次に target[1]、target[2]... と順に見ていき、maxvalue より大きい要素が見つかるたびに、maxvalue をその値に更新する。

こうすると、maxvalue には「ここまでで見た中でいちばん大きい値(暫定的な最大値)」が入り続け、最後まで見終わると本当の最大値になります。

In [22]:
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
No description has been provided for this image

ここでは 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 章で学んだやり方(先頭を暫定の最大値にして更新する)で求めてください。

In [ ]:
data = [12, 5, 28, 9, 17]

# for 文で合計を求めて表示してください


# for 文で最大値を求めて表示してください。max は使わない

4. フローチャートで for 文を組む¶

ここまで Python で書いてきた繰り返しを、フローチャートでも表せます。Flowchart Maker では、繰り返しを for 繰り返しブロック(ひし形)で表します。

Flowchart Maker の for 繰り返しブロック。ひし形に for i in range(0, 5): と書かれ、次あり側でループの中身へ、次なし側で抜ける。

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 がそのまま使えます。

Flowchart Maker のフローチャート。for i in range(0, len(numbers)): のひし形から、次あり側で numbers[i] を出力し、戻るでひし形へ戻る。

Python の for i in range(0, len(numbers)): と、まったく同じ処理を表しています。

4.3 総和を求める¶

総和もフローチャートで作れます。 リストnumbers の合計を for ブロックで求めることを考えます。 ループに入る前に total = 0 としておき、次あり の先で total = total + numbers[i] を繰り返し、次なし に抜けたあとで total を出力すれば合計が得られます。

Flowchart Maker のフローチャート。total を 0 に初期化し、for i in range(0, len(numbers)): のひし形の次あり側で total = total + numbers[i] を繰り返し、次なし側に抜けたあと total を出力する。

Python で書いた総和のコードと、同じ流れになっていることを確かめてください。最大値を求めるときも、maxvalue = numbers[0] から始めて、ループの中で if と更新を行う、という同じ形で作れます。

5. 演習: 学籍番号の各桁を for 文で処理する¶

最後に、この回で学んだことを、自分の 学籍番号後半 5 桁 を使って練習します。次のように、後半 5 桁の数字を1 つずつ要素にしたリストdigits を用意します(digits を作る式の仕組みは、いまは気にしなくてかまいません。5 つの数字が順に要素として並ぶ、とだけ分かれば十分です)。

In [23]:
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 をいろいろ変えて、結果が変わることも確かめましょう。 それぞれ別のセルに書いて、実行して確かめてください。

In [1]:
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 つです。