[Python]多重ループ(forループ)から抜ける方法

Python フロー制御

Pythonで多重ループ(forループ/whileループ)から抜ける方法について、本記事では、for〜else文を利用する方法や確認変数を利用する方法、そして条件に合致したら即returnする方法などについてまとめます。最後にそれぞれの処理速度も比較してみます。

確認した環境

  • OS: Ubuntu16.4LTS
  • Python 3.7.2

for〜else文を使う方法

forループやwhileループは以下のようにelse節を取ることができます。

for ():
    処理1
else:
    処理2
  • forループの処理1が全部終わった場合: 処理2(else節の中身)を実行
  • forループ中に処理1がbreakされた場合: else節は実行されずに次の処理を実行

これを利用すると多重ループを抜けることができます。
例として、以下の2重配列(3×3)からforループを使って所望の値を見つける処理を考えます。
つまり、二重のforループ処理において、条件に合致した値が見つかったらループを抜ける処理です。

# 多重配列(3×3)
>>> h = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
  • 二重ループを抜けるコード例
for i in range(3):
    for j in range(3):
        print('--- inner:({}, {})={}'.format(i, j, h[i][j]))
        if h[i][j] == 4:
            print('Find:{}'.format(h[i][j]))
            break
    else:   # forループが満了すると、このelse節が実行される
        print('continue outer')
        continue
    print('break outer') #forループがbreakするとここに飛ぶ
    break

以下に出力結果を示します。forループの途中でbreakした後、else節は実行されずに次の処理に移行し、2重ループを抜けることが出来ました。

--- inner:(0, 0)=0
--- inner:(0, 1)=1
--- inner:(0, 2)=2
continue outer  ★forループの処理が全部終わり、else節を実行
--- inner:(1, 0)=3
--- inner:(1, 1)=4
Find:4
break outer   ★forループがbreakされ、else節の次の処理を実行

<参考記事>for・while文でのelse節の使い方

結果変数(フラグ)を使う方法

前項のfor〜else節は、for部におけるelse節を理解していないと少し難しいと感じるかもしれません。そのような場合は、少し冗長ですが結果変数(フラグ)を使う方法が考えられます。
下記にコード例を示します。

flg = True # 結果変数(フラグ)を設定
for i in range(3):
    for j in range(3):
        print('--- inner:({}, {})={}'.format(i, j, h[i][j]))
        if h[i][j] == 4:
            print('Find:{}'.format(h[i][j]))
            flg = False # 結果変数(フラグ)がFalseの場合ループを抜ける
            break
    if flg == True:    
        print('continue outer')
        
    if flg == False: # 結果変数(フラグ)がFalseの場合ループを抜ける
        print('break outer')
        break  

出力結果を以下に示します。無事、2重ループを抜けています。

--- inner:(0, 0)=0
--- inner:(0, 1)=1
--- inner:(0, 2)=2
continue outer
--- inner:(1, 0)=3
--- inner:(1, 1)=4
Find:4
break outer

条件を満たしたら即returnする

ループ部分を関数で記述して、条件を満たしたら即returnで値を返して抜ける方法です。

def inner(arr):
    for i in range(3):
        for j in range(3):
            print('--- inner:({}, {})={}'.format(i, j, arr[i][j]))
            if arr[i][j] == 4:
                print('Find:{}'.format(arr[i][j]))
                print('break outer')
                return False ★条件を満たしたらreturnで抜ける
        print('continue outer')
    return True 

inner(h)

出力結果を以下に示します。

--- inner:(0, 0)=0
--- inner:(0, 1)=1
--- inner:(0, 2)=2
continue outer
--- inner:(1, 0)=3
--- inner:(1, 1)=4
Find:4
break outer

<番外>itertoolsモジュールを使う方法(ループを使わない)

ループを複数回すということは、複数の変数の組み合わせを確認していることになります。よって、itertoolsモジュールを使って、パラメータの全ての組み合わせを評価する方法も考えられます。

import itertools

H, W = 3, 3
for (i, j) in itertools.product(range(H), range(W)):
    print('--- inner:({}, {})={}'.format(i, j, h[i][j]))
    if h[i][j] == 4:
        print('Find:{}'.format(h[i][j]))
        break

出力結果は以下です。目的の動作は達成できていますね。

--- inner:(0, 0)=0
--- inner:(0, 1)=1
--- inner:(0, 2)=2
--- inner:(1, 0)=3
--- inner:(1, 1)=4
Find:4

それぞれの方法の速度を比較

最後に、上記の3つの方法+番外編の速度を比較してみたいと思います。前提条件は、

  • 異なる整数値を各要素に持つ100x100x100の3次元配列を生成
  • この中からある指定の値を見つけたらループを抜ける

すなわち、3重ループからぬけ出すのはどれが一番効率が良いか?を比較しました。
コード例はこちらです。下記に、100回繰り返した結果をヒストグラムで表しました。

          図 多重ループを抜ける方法各種の速度比較

絶対値はPCの性能によるので相対的に比較すると、itertoolsモジュールを使った場合は、若干遅くなるものの、どの方法を使ってもほぼ同等という結果になりました。
結局、どれを使うかは個人の好みやどういう場面で使っているかによるのかと思います。

まとめ

今回は、多重のforループ(whileループ)を抜ける方法として、

  • for〜else文を使った方法
  • 結果変数を使った方法
  • 関数にまとめてreturnする方法

についてまとめました。
また、それぞれの処理速度についても比較しましたが、特に差はみられませんでした。

参考書籍

書籍でもう少し詳しく学びたい場合はこちらもどうぞ。筆者もかなり参考にさせてもらっています!

シェアする
ひびきをフォローする
Hbk project