メインコンテンツへスキップ
Lesson6 / 7

ネストしたループ

目次

このレッスンで学ぶこと

  • ネストしたループとは何か
  • 二重ループの基本
  • ネストしたループの実用例
  • ループのネストを減らす方法

ネストしたループとは

ネストしたループは、ループの内側に別のループを配置した構造です。外側のループが1回繰り返される間に、内側のループが全て実行されます。2次元のデータ処理や全組み合わせの生成に使用されます。

ネストしたループの基本構造

Python
for 外側変数 in 外側コレクション:      # 外側のループ
    for 内側変数 in 内側コレクション:  # 内側のループ
        処理                         # 内側のループが完全に実行される

ネストしたループの構成要素

要素説明
外側のループ繰り返しの外側の層for i in range(3):
内側のループ繰り返しの内側の層for j in range(3):
インデントループの範囲を示す4文字ずつ増える
実行回数外側×内側3×3 = 9回

ネストしたループの特徴

  • 外側のループが1回実行されるごとに、内側のループが全て実行される
  • 実行回数は外側のループ数×内側のループ数
  • インデントが重要(正しいインデントでのみ正常に動作)
  • 2次元データや表形式データの処理に最適

簡単な例

Python
# 3×3のパターン(9回実行)
for i in range(3):
    for j in range(3):
        print(f"({i}, {j})", end=" ")
    print()  # 改行

# 実行結果:
# (0, 0) (0, 1) (0, 2)
# (1, 0) (1, 1) (1, 2)
# (2, 0) (2, 1) (2, 2)

# 掛け算表(2×3)
for i in range(1, 3):
    for j in range(1, 4):
        print(f"{i}×{j}={i*j}", end=" ")
    print()

# 実行結果:
# 1×1=1 1×2=2 1×3=3
# 2×1=2 2×2=4 2×3=6

なぜネストしたループが必要なのか?

2次元のデータや、すべての組み合わせを処理したい場合、ループの中にループを書く必要があります。

Python
# 九九の表
for i in range(1, 4):
    for j in range(1, 4):
        result = i * j
        print(f"{i} × {j} = {result}")

実行結果:

1 × 1 = 1
1 × 2 = 2
1 × 3 = 3
2 × 1 = 2
2 × 2 = 4
2 × 3 = 6
3 × 1 = 3
3 × 2 = 6
3 × 3 = 9

ネストしたループを使うことで、複雑な組み合わせ処理ができます。

💡 豆知識: 「ネスト(nest)」は英語で「巣」という意味です。プログラミングでは「入れ子構造」を指し、ループの中にさらにループがある状態を表します。


ネストしたループの基本

二重ループの構文

機能: 外側のループの各繰り返しごとに、内側のループが全て実行されます。

書き方:

Python
for 外側変数 in 外側コレクション:
    for 内側変数 in 内側コレクション:
        処理

用途: 2次元データの処理、全組み合わせの生成、表の作成

注意点:

  • 実行回数は外側×内側の回数になる
  • インデントを正しく行う
  • パフォーマンスに注意(大量データでは遅くなる)
Python
# 基本的な使い方
for i in range(3):
    for j in range(3):
        print(f"({i}, {j})")

実行結果:

(0, 0)
(0, 1)
(0, 2)
(1, 0)
(1, 1)
(1, 2)
(2, 0)
(2, 1)
(2, 2)

基本パターン

パターン1: 掛け算表

Python
# 3×3の掛け算表
print("=== 掛け算表 ===")
for i in range(1, 4):
    for j in range(1, 4):
        result = i * j
        print(f"{result:3}", end="")
    print()  # 改行

実行結果:

=== 掛け算表 ===
  1  2  3
  2  4  6
  3  6  9

パターン2: リストのリスト(2次元リスト)

機能: 2次元リスト(表形式のデータ)の各要素にアクセスします。

書き方:

Python
forin リスト:
    for 要素 in:
        処理

用途: 表データの処理、行列計算、座席配置

注意点: インデックスが必要な場合はenumerate()を使う

Python
# 2次元リストの処理
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

print("=== 2次元リスト ===")
for row in matrix:
    for value in row:
        print(value, end=" ")
    print()

実行結果:

=== 2次元リスト ===
1 2 3
4 5 6
7 8 9

パターン3: 全組み合わせ

Python
# すべての組み合わせを生成
fruits = ["りんご", "バナナ"]
colors = ["赤", "黄"]

print("=== 組み合わせ ===")
for fruit in fruits:
    for color in colors:
        print(f"{color}{fruit}")

実行結果:

=== 組み合わせ ===
赤いりんご
黄いりんご
赤いバナナ
黄いバナナ

具体例

例1: 座席表

Python
rows = ["A", "B", "C"]
seats = [1, 2, 3, 4]

print("=== 座席表 ===")
for row in rows:
    for seat in seats:
        print(f"{row}{seat}", end=" ")
    print()

実行結果:

=== 座席表 ===
A1 A2 A3 A4
B1 B2 B3 B4
C1 C2 C3 C4

例2: 九九の表(完全版)

Python
print("=== 九九の表 ===")
print("   ", end="")
for i in range(1, 10):
    print(f"{i:3}", end="")
print()
print("-" * 31)

for i in range(1, 10):
    print(f"{i} |", end="")
    for j in range(1, 10):
        result = i * j
        print(f"{result:3}", end="")
    print()

実行結果:

=== 九九の表 ===
     1  2  3  4  5  6  7  8  9
-------------------------------
1 |  1  2  3  4  5  6  7  8  9
2 |  2  4  6  8 10 12 14 16 18
3 |  3  6  9 12 15 18 21 24 27
4 |  4  8 12 16 20 24 28 32 36
5 |  5 10 15 20 25 30 35 40 45
6 |  6 12 18 24 30 36 42 48 54
7 |  7 14 21 28 35 42 49 56 63
8 |  8 16 24 32 40 48 56 64 72
9 |  9 18 27 36 45 54 63 72 81

例3: カレンダーの表示

Python
# 簡易カレンダー(4週間)
weeks = 4
days = 7
day_count = 1

print("=== カレンダー ===")
print("日 月 火 水 木 金 土")

for week in range(weeks):
    for day in range(days):
        print(f"{day_count:2}", end=" ")
        day_count += 1
    print()

実行結果:

=== カレンダー ===
日 月 火 水 木 金 土
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28

例4: パターン表示

Python
# 三角形のパターン
print("=== 三角形 ===")
for i in range(1, 6):
    for j in range(i):
        print("*", end="")
    print()

print("\n=== 逆三角形 ===")
for i in range(5, 0, -1):
    for j in range(i):
        print("*", end="")
    print()

実行結果:

=== 三角形 ===
*
**
***
****
*****

=== 逆三角形 ===
*****
****
***
**
*

例5: テストの組み合わせ

Python
# すべてのテストケースを生成
sizes = ["S", "M", "L"]
colors = ["赤", "青", "緑"]

print("=== 商品バリエーション ===")
count = 0
for size in sizes:
    for color in colors:
        count += 1
        print(f"{count}. {size}サイズ - {color}")

print(f"\n合計: {count}種類")

実行結果:

=== 商品バリエーション ===
1. Sサイズ - 赤
2. Sサイズ - 青
3. Sサイズ - 緑
4. Mサイズ - 赤
5. Mサイズ - 青
6. Mサイズ - 緑
7. Lサイズ - 赤
8. Lサイズ - 青
9. Lサイズ - 緑

合計: 9種類

例6: 2次元リストの合計

Python
# 各行の合計を計算
scores = [
    [85, 92, 78],
    [90, 88, 95],
    [76, 82, 89]
]

print("=== 学生の成績 ===")
for i, student_scores in enumerate(scores, 1):
    total = 0
    for score in student_scores:
        total += score
    average = total / len(student_scores)
    print(f"学生{i}: 合計 = {total}点, 平均 = {average:.1f}点")

実行結果:

=== 学生の成績 ===
学生1: 合計 = 255点, 平均 = 85.0点
学生2: 合計 = 273点, 平均 = 91.0点
学生3: 合計 = 247点, 平均 = 82.3点

ネストしたループとbreak/continue

breakで内側のループを抜ける

Python
# 内側のループだけbreak
for i in range(3):
    print(f"\n外側: {i}")
    for j in range(5):
        if j == 3:
            print("  内側をbreak")
            break
        print(f"  内側: {j}")

実行結果:

外側: 0
  内側: 0
  内側: 1
  内側: 2
  内側をbreak

外側: 1
  内側: 0
  内側: 1
  内側: 2
  内側をbreak

外側: 2
  内側: 0
  内側: 1
  内側: 2
  内側をbreak

外側のループも抜けたい場合

Python
# フラグを使って外側も抜ける
found = False

for i in range(5):
    for j in range(5):
        if i * j == 12:
            print(f"見つけました: {i} × {j} = 12")
            found = True
            break
    if found:
        break

実行結果:

見つけました: 3 × 4 = 12

continueの使用

Python
# 特定の組み合わせをスキップ
for i in range(1, 4):
    for j in range(1, 4):
        if i == j:
            continue  # 同じ数の組み合わせはスキップ
        print(f"({i}, {j})")

実行結果:

(1, 2)
(1, 3)
(2, 1)
(2, 3)
(3, 1)
(3, 2)

ネストを減らす方法

方法1: 関数に分割

Python
# ネストが深い例
for i in range(3):
    for j in range(3):
        for k in range(3):
            result = i * j * k
            print(f"{i} × {j} × {k} = {result}")

# 関数に分割(読みやすい)
def calculate_product(i, j, k):
    result = i * j * k
    print(f"{i} × {j} × {k} = {result}")

for i in range(3):
    for j in range(3):
        for k in range(3):
            calculate_product(i, j, k)

方法2: リスト内包表記

Python
# ネストしたループ
result = []
for i in range(3):
    for j in range(3):
        result.append((i, j))

# リスト内包表記(簡潔)
result = [(i, j) for i in range(3) for j in range(3)]
print(result)

実行結果:

[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]

方法3: 早期continue

Python
# ネストを減らす
for i in range(5):
    if i % 2 != 0:
        continue  # 奇数はスキップ

    for j in range(5):
        if j % 2 != 0:
            continue  # 奇数はスキップ

        print(f"({i}, {j})")

よくある間違い

間違い1: インデントの誤り

Python
# 間違い: インデントがおかしい
for i in range(3):
    for j in range(3):
    print(f"{i}, {j}")  # エラー

# 正しい
for i in range(3):
    for j in range(3):
        print(f"{i}, {j}")

間違い2: 変数名の重複

Python
# 問題がある例
for i in range(3):
    for i in range(3):  # 外側のiを上書き
        print(i)

# 正しい
for i in range(3):
    for j in range(3):  # 別の変数名
        print(f"{i}, {j}")

間違い3: 実行回数の誤解

Python
# 10回だと思っている?
count = 0
for i in range(10):
    for j in range(10):
        count += 1

print(count)  # 100回(10 × 10)

間違い4: breakの範囲

Python
# 外側も抜けると思っている
for i in range(3):
    for j in range(3):
        if j == 1:
            break  # 内側だけ抜ける

# フラグが必要
found = False
for i in range(3):
    for j in range(3):
        if j == 1:
            found = True
            break
    if found:
        break

間違い5: パフォーマンス無視

Python
# 非効率な例(1,000,000回実行される)
for i in range(1000):
    for j in range(1000):
        result = i + j

# 必要な処理だけに絞る
for i in range(100):
    for j in range(100):
        result = i + j

練習問題

問題1(基礎)⭐☆☆

1から3までの数について、それぞれ1から3までを掛けた結果を表示してください。

💡 ヒント

二重ループを使います。

✅ 解答例
Python
for i in range(1, 4):
    for j in range(1, 4):
        result = i * j
        print(f"{i} × {j} = {result}")

実行結果:

1 × 1 = 1
1 × 2 = 2
1 × 3 = 3
2 × 1 = 2
2 × 2 = 4
2 × 3 = 6
3 × 1 = 3
3 × 2 = 6
3 × 3 = 9

解説: 外側のループで1〜3、内側のループで1〜3を掛け算しています。


問題2(基礎)⭐☆☆

以下のパターンを表示してください。

*
**
***
****
💡 ヒント

外側のループで行数、内側のループで星の数を制御します。

✅ 解答例
Python
for i in range(1, 5):
    for j in range(i):
        print("*", end="")
    print()

実行結果:

*
**
***
****

解説: i行目にはi個の星を表示しています。


問題3(応用)⭐⭐☆

以下の2次元リストの全要素の合計を計算してください。

Python
numbers = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]
💡 ヒント

二重ループですべての要素を足します。

✅ 解答例
Python
numbers = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

total = 0
for row in numbers:
    for value in row:
        total += value

print(f"合計: {total}")

実行結果:

合計: 45

解説: 外側のループで各行を取得し、内側のループで行内の各値を合計に加算しています。


まとめ

このレッスンでは、ネストしたループで多重反復を扱う方法を学びました。

  • ループの中にループを書くことで、行列や組み合わせを処理できます。
  • 外側と内側の役割を分けて設計すると、処理意図が明確になります。
  • ネストが深くなるほど計算量が増える点を意識する必要があります。
  • インデックスやカウンタの扱いを整理するとバグを減らせます。
  • 小さなデータで出力を確認しながら段階的に組み立てることが重要です。