入れ子のループ:繰り返しの中の繰り返し#

はじめに#

これまでの記事では、「for文」と「while文」という繰り返し処理の方法と、「break文」と「continue文」というループを制御する方法を学びました。

今回は、「入れ子のループ」という技術について学びましょう。入れ子のループとは、ループの中にさらにループを入れることです。例えるなら、「一週間の毎日(外側のループ)、朝・昼・夜と3回食事をする(内側のループ)」といった状況を表現できます。

入れ子のループを使うと、表形式のデータを扱ったり、複雑なパターンを作ったりすることができます。この記事では、基本から応用まで詳しく解説していきます。

入れ子のループの基本#

入れ子のループは、ループの中に別のループを入れることで作成します。外側のループが1回実行されるごとに、内側のループが最初から最後まで実行されます。

基本的な形は次のとおりです。

# 外側のループ
for 外側の変数 in 外側のシーケンス:
    # 外側のループの処理

    # 内側のループ
    for 内側の変数 in 内側のシーケンス:
        # 内側のループの処理

    # 外側のループの続き

簡単な例で見てみましょう。

>
# 基本的な入れ子のループ
print("入れ子のループの基本例:")

for i in range(3):  # 外側のループ
    print(f"外側のループ: i = {i}")

    for j in range(2):  # 内側のループ
        print(f"  内側のループ: j = {j}")

    print("外側のループの1回分の終わり")
入れ子のループの基本例:
外側のループ: i = 0
  内側のループ: j = 0
  内側のループ: j = 1
外側のループの1回分の終わり
外側のループ: i = 1
  内側のループ: j = 0
  内側のループ: j = 1
外側のループの1回分の終わり
外側のループ: i = 2
  内側のループ: j = 0
  内側のループ: j = 1
外側のループの1回分の終わり

この例では、外側のループが3回(i=0, 1, 2)、内側のループが各回で2回(j=0, 1)実行されるため、内側のループの処理は合計で3 × 2 = 6回実行されます。

入れ子のwhileループ#

入れ子のループは、for文だけでなくwhile文でも作成できます。また、for文とwhile文を組み合わせることも可能です。

>
# while文を使った入れ子のループ
print("while文を使った入れ子のループ:")

# 教科書の各章と問題を確認する例
chapter = 1
while chapter <= 3:
    print(f"第{chapter}章を勉強中")

    problem = 1
    while problem <= 2:
        print(f"  問題{chapter}-{problem}を解く")
        problem += 1

    print(f"第{chapter}章を終了")
    chapter += 1
while文を使った入れ子のループ:
第1章を勉強中
  問題1-1を解く
  問題1-2を解く
第1章を終了
第2章を勉強中
  問題2-1を解く
  問題2-2を解く
第2章を終了
第3章を勉強中
  問題3-1を解く
  問題3-2を解く
第3章を終了

この例では、for文の場合と同様に、外側のループが1回実行されるごとに、内側のループが最初から最後まで実行されます。

入れ子のループとbreak文#

前回の記事で学んだbreak文は、入れ子のループでも使うことができます。ただし注意が必要なのは、break文は自分が属する「最も内側のループ」だけを抜けるということです。

>
# 入れ子のループとbreak文
print("入れ子のループとbreak文:")

for i in range(3):
    print(f"外側のループ: i = {i}")

    for j in range(4):
        print(f"  内側のループ: j = {j}")

        if j == 1 and i == 1:
            print("  条件に一致したのでbreak")
            break  # 内側のループ(j)だけを抜ける

    print("外側のループの1回分の終わり")
入れ子のループとbreak文:
外側のループ: i = 0
  内側のループ: j = 0
  内側のループ: j = 1
  内側のループ: j = 2
  内側のループ: j = 3
外側のループの1回分の終わり
外側のループ: i = 1
  内側のループ: j = 0
  内側のループ: j = 1
  条件に一致したのでbreak
外側のループの1回分の終わり
外側のループ: i = 2
  内側のループ: j = 0
  内側のループ: j = 1
  内側のループ: j = 2
  内側のループ: j = 3
外側のループの1回分の終わり

この例では、i == 1かつj == 1の条件が満たされたときにbreakが実行されますが、内側のループ(j)だけが終了し、外側のループ(i)は続行されています。

入れ子のループとcontinue文#

continue文も入れ子のループで使うことができます。break文と同様に、continue文も自分が属する「最も内側のループ」だけに影響します。

>
print("入れ子のループとcontinue文:")

for i in range(3):
    print(f"外側のループ: i = {i}")

    for j in range(4):
        if j == 1 and i == 1:
            print(f"  i = {i}, j = {j} の処理をスキップ")
            continue  # 内側のループ(j)の現在の繰り返しをスキップ

        print(f"  内側のループ: i = {i}, j = {j}")

    print("外側のループの1回分の終わり")
入れ子のループとcontinue文:
外側のループ: i = 0
  内側のループ: i = 0, j = 0
  内側のループ: i = 0, j = 1
  内側のループ: i = 0, j = 2
  内側のループ: i = 0, j = 3
外側のループの1回分の終わり
外側のループ: i = 1
  内側のループ: i = 1, j = 0
  i = 1, j = 1 の処理をスキップ
  内側のループ: i = 1, j = 2
  内側のループ: i = 1, j = 3
外側のループの1回分の終わり
外側のループ: i = 2
  内側のループ: i = 2, j = 0
  内側のループ: i = 2, j = 1
  内側のループ: i = 2, j = 2
  内側のループ: i = 2, j = 3
外側のループの1回分の終わり

この例では、i == 1かつj == 1の条件が満たされたときにcontinueが実行され、その繰り返しだけがスキップされ、内側のループの次の繰り返し(j = 2)に進みます。

実用例:かけ算表の作成#

入れ子のループの実用的な例として、九九のようなかけ算表を作成してみましょう。

>
# 掛け算表の作成
print("掛け算表(九九):")

# 1から9までの掛け算表
for i in range(1, 10):
    for j in range(1, 10):
        result = i * j
        print(f"{result:2d}", end=" ")  # 2桁で整列して表示
    print()  # 行の終わりで改行
掛け算表(九九):
 1  2  3  4  5  6  7  8  9
 2  4  6  8 10 12 14 16 18
 3  6  9 12 15 18 21 24 27
 4  8 12 16 20 24 28 32 36
 5 10 15 20 25 30 35 40 45
 6 12 18 24 30 36 42 48 54
 7 14 21 28 35 42 49 56 63
 8 16 24 32 40 48 56 64 72
 9 18 27 36 45 54 63 72 81

この例では、入れ子のループを使って9×9のかけ算表を作成しています。外側のループが行(i)、内側のループが列(j)を処理し、各セルにi * jの結果を表示しています。

実用例:パターンの出力#

入れ子のループを使うと、さまざまな模様やパターンを出力することができます。例えば、次のようなアスタリスクを使ったパターンを考えてみましょう。

>
# パターンの出力例
print("パターン出力の例:")

# 三角形のパターン
height = 5

print("\n三角形パターン:")
for i in range(1, height + 1):
    for j in range(i):
        print("*", end="")
    print()  # 行の終わりで改行

# 逆三角形のパターン
print("\n逆三角形パターン:")
for i in range(height, 0, -1):
    for j in range(i):
        print("*", end="")
    print()  # 行の終わりで改行

# ピラミッドパターン
print("\nピラミッドパターン:")
for i in range(1, height + 1):
    # スペースを出力
    for j in range(height - i):
        print(" ", end="")

    # アスタリスクを出力
    for j in range(2 * i - 1):
        print("*", end="")

    print()  # 行の終わりで改行
パターン出力の例:

三角形パターン:
*
**
***
****
*****

逆三角形パターン:
*****
****
***
**
*

ピラミッドパターン:
    *
   ***
  *****
 *******
*********

これらの例では、外側のループが行数を、内側のループが各行の文字数を制御しています。「ピラミッドパターン」の例では、各行に適切な数のスペースとアスタリスクを出力するために2つの内側ループを使っています。

まとめ#

この記事では、Pythonの入れ子のループ(ループの中のループ)について学びました。

  • 入れ子のループは、ループの中に別のループを配置することで、複数次元の繰り返し処理を実現する
  • 外側のループが1回実行されるごとに、内側のループが最初から最後まで実行される
  • 入れ子のループの実行回数は、各ループの繰り返し回数の掛け算で求められる
  • 入れ子のループは、表形式のデータ処理や模様の出力など、様々な場面で役立つ
  • break文とcontinue文は、自分が属する最も内側のループだけに影響する

入れ子のループは、複雑なデータ構造の処理や、複数の条件に基づいたアルゴリズムの実装に非常に役立ちます。効率的に使いこなせるようになれば、より柔軟なプログラムを書けるようになるでしょう。