ネスト(入れ子)したループでは、「どのループを抜けるのか」をはっきり示すことが大切です。初心者がつまずきやすいポイントを避けつつ、使いどころ・避けどころ・代替手段を具体例で解説します。読み手が迷わないように、目的をコードで明確に表しましょう。
基本の考え方(どのループを抜ける?)
- ポイント:
breakは「いま書いているループ(いちばん内側)」だけを抜けます。外側のループは続行されます。 - 落とし穴: 「外側のループまで抜けたい」つもりで
breakを使っても、内側しか止まりません。 - 指針: 目的が「内側だけ止める」のか「ループ全体を止める」のかを最初に決める。後者ならフラグや
returnを検討。
例題1: 行の中で最初の条件が見つかったら、その行の探索だけを終える
「各行の中で最初に偶数が見つかったら、その行は探索終了して次の行へ進む」例です。内側のループだけ break するのが自然です。
grid = [
[3, 5, 8, 11],
[7, 9, 13],
[2, 4, 6]
]
for row in grid:
for x in row:
if x % 2 == 0:
print("この行の最初の偶数:", x, "(行:", row, ")")
break # 内側(rowを走査中のループ)だけ抜ける
Python- ねらい: 行ごとに「最初の偶数だけ知りたい」なら、内側の
breakが最短で明快。 - 効果: 各行の偶数が見つかった瞬間に無駄な探索をやめ、次の行へ進める。
例題2: グリッド中で条件が見つかったら「全体の探索を終了」する
「最初に偶数を一つでも見つけたら、もう全体をやめたい」なら、内側の break だけでは不十分。フラグや関数化+return を使うと読みやすくなります。
方法A: フラグ変数で外側も止める
found = False
for i, row in enumerate(grid):
for j, x in enumerate(row):
if x % 2 == 0:
print("最初に見つけた偶数:", x, "(位置: 行", i, "列", j, ")")
found = True
break # 内側を抜ける
if found:
break # 外側も抜ける
Python- メリット: どのループを止めるかがコードの位置で理解できる。
- デメリット: フラグの導入で少し冗長だが、意図は明確。
方法B: 関数にして return で「処理全体」を終了
def find_first_even(grid):
for i, row in enumerate(grid):
for j, x in enumerate(row):
if x % 2 == 0:
return (x, i, j) # 関数ごと終了
return None
result = find_first_even(grid)
if result:
x, i, j = result
print("最初の偶数:", x, "(位置: 行", i, "列", j, ")")
else:
print("偶数は見つかりませんでした")
Python- メリット: 「見つかったら処理終わり」を最短・明快に表現できる。テストもしやすい。
- デメリット: 関数化が前提。スクリプト直書きなら一手間増える。
例題3: 多段ネストで「どこを抜けるか」分かりづらい場合の整理
深いネストは読み手の負担が大きいので、分解して「役割ごとに止める」形にすると理解しやすくなります。
NG例(読みづらい)
for a in A:
for b in B:
for c in C:
if is_target(a, b, c):
break # これは c ループだけを抜ける。意図が曖昧
# ここで何が起きてほしい?さらに外側も止めたい?
Python改善例(関数で責務を分ける)
def find_in_C(a, b, C):
for c in C:
if is_target(a, b, c):
return c # c探索の責務はここで終わり
return None
found = None
for a in A:
for b in B:
c = find_in_C(a, b, C)
if c is not None:
found = (a, b, c)
break # bループを止める
if found:
break # aループも止める
print("結果:", found)
Python- 効果: 「どの段で終わるか」を段階的に可視化でき、意図が伝わる。
- 指針: 深いネストは関数分割+早期
returnが有力。
例題4: 1行の中で複数条件のチェックと早期打ち切り(ガード的 break)
「一つでも不正が見つかったら、その行の検証は打ち切る」ようなバリデーションは、内側 break が適しています。
rows = [
{"id": 1, "age": 20, "score": 80},
{"id": 2, "age": -5, "score": 70}, # 不正
{"id": 3, "age": 30, "score": 50}
]
for row in rows:
for field in ("age", "score"):
value = row[field]
if field == "age" and value < 0:
print("行ID", row["id"], "で不正な年齢:", value)
break # この行の検証はここで打ち切って次の行へ
if field == "score" and not (0 <= value <= 100):
print("行ID", row["id"], "で不正なスコア:", value)
break
Python- ねらい: 「この行はもうダメ」と分かった時点で余計なチェックをしない。
- 注意: 多条件が増えたら、検証ロジックを関数化するとより明解。
使い分けの指針(まとめ)
- 内側だけ止めたい: その場の
breakがシンプルで分かりやすい。 - 全体の探索を止めたい: フラグ+外側で
break、または関数化してreturnの方が意図が明確。 - 深いネストで混乱しそう: 関数分割し、各段階で早期
return。読みやすさとテスト容易性が向上。 - “どのループを抜けるか”が曖昧: コードの位置で明示するか、名前付き関数に分けて責務をはっきりさせる。
追加の練習課題
- 課題: 2次元リストで「最初に現れる3の倍数」を見つけ、見つかったら全体の探索を終了して位置を出力。
- ヒント: フラグ方式と関数方式の両方で解いてみて、可読性の違いを比べる
模範解答
フラグ方式(外側ループも止める)
grid = [
[2, 5, 7],
[4, 9, 11],
[8, 13, 15]
]
found = False
for i, row in enumerate(grid):
for j, val in enumerate(row):
if val % 3 == 0: # 3の倍数を判定
print("最初に見つけた3の倍数:", val, "(位置: 行", i, "列", j, ")")
found = True
break # 内側ループを抜ける
if found:
break # 外側ループも抜ける
if not found:
print("3の倍数は見つかりませんでした")
Python実行結果例
最初に見つけた3の倍数: 9 (位置: 行 1 列 1 )
関数方式(returnで処理全体を終了)
def find_first_multiple_of_three(grid):
for i, row in enumerate(grid):
for j, val in enumerate(row):
if val % 3 == 0:
return (val, i, j) # 見つかったら関数ごと終了
return None # 見つからなかった場合
grid = [
[2, 5, 7],
[4, 9, 11],
[8, 13, 15]
]
result = find_first_multiple_of_three(grid)
if result:
val, i, j = result
print("最初に見つけた3の倍数:", val, "(位置: 行", i, "列", j, ")")
else:
print("3の倍数は見つかりませんでした")
Python実行結果例
最初に見つけた3の倍数: 9 (位置: 行 1 列 1 )
まとめ
- フラグ方式: ループを外側まで止めたいときに便利。処理の流れが見える。
- 関数方式: 「見つかったら処理全体を終了」という意図を最短で表現できる。テストや再利用にも向いている。
👉 初心者はまず フラグ方式で「どのループを抜けるか」を理解し、慣れてきたら 関数方式でよりシンプルに書けるようになると良いです。


