note.nkmk.me

Pythonのfor文によるループ処理(range, enumerate, zipなど)

Date: 2018-04-04 / Modified: 2018-07-24 / tags: Python

Pythonのfor文によるループ処理について説明する。

  • 基本的な文法
    • Pythonのfor文の基本的な使い方
    • 条件によって途中で終了: break
    • 特定の要素の処理をスキップ: continue
    • forループ正常終了後の処理: else
  • for文で使うと便利な関数
    • インデックス(カウンタ): range()関数
    • リストの要素とインデックス: enumerate()関数
    • 複数リストの要素(複数変数): zip()関数
    • 複数リストの要素とインデックス: enumerate(), zip()関数
    • 逆順: reversed()関数
    • 多重ループ: itertools.product()関数
  • その他トピック
    • 辞書オブジェクトのforループ
    • リスト内包表記
スポンサーリンク

Pythonのfor文の基本的な使い方

C系のプログラミング言語のfor文(forループ)はカウンタ変数(インデックス)と継続条件を使って記述する。

for(int i = 0; i < 10; i++)
    処理

Pythonのfor文はC系とは違い、カウンタ変数(インデックス)を使わずに記述する。変数名は任意の名称。

for 変数名 in イテラブルオブジェクト:
    処理

他の言語におけるforeach文に相当し、リスト(配列)などのイテラブルオブジェクトの要素が順番に変数に代入され処理が行われる。すべての要素に対して処理が繰り返される。

具体例は以下の通り。

l = ['Alice', 'Bob', 'Charlie']

for name in l:
    print(name)
# Alice
# Bob
# Charlie
source: for_usage.py

条件によって途中で終了: break

for文の途中で処理を終了したい場合はbreakを使う。

l = ['Alice', 'Bob', 'Charlie']

for name in l:
    if name == 'Bob':
        print('!!BREAK!!')
        break
    print(name)
# Alice
# !!BREAK!!
source: for_usage.py

特定の要素の処理をスキップ: continue

特定の要素に対する処理をスキップしたい場合はcontinueを使う。

breakはforループ全体が終了するが、continueはその要素に対するcontinue文以降の処理がスキップされるのみでforループは継続し次の要素の処理が実行される。

l = ['Alice', 'Bob', 'Charlie']

for name in l:
    if name == 'Bob':
        print('!!SKIP!!')
        continue
    print(name)
# Alice
# !!SKIP!!
# Charlie
source: for_usage.py

forループ正常終了後の処理: else

for文によるループが終わりまで実行された後に何らかの処理を行いたい場合はelseを使う。

l = ['Alice', 'Bob', 'Charlie']

for name in l:
    print(name)
else:
    print('!!FINISH!!')
# Alice
# Bob
# Charlie
# !!FINISH!!
source: for_usage.py

breakによって途中で終了した場合はelseの処理は実行されない。

for name in l:
    if name == 'Bob':
        print('!!BREAK!!')
        break
    print(name)
else:
    print('!!FINISH!!')
# Alice
# !!BREAK!!
source: for_usage.py

continueの場合はforループが最後まで到達するのでelseの処理が実行される。

for name in l:
    if name == 'Bob':
        print('!!SKIP!!')
        continue
    print(name)
else:
    print('!!FINISH!!')
# Alice
# !!SKIP!!
# Charlie
# !!FINISH!!
source: for_usage.py

elsecontinueを組み合わせると多重ループの内側のループから一気にbreakで抜け出すことができる。以下の記事を参照。

インデックス(カウンタ): range()関数

Pythonのfor文でインデックス(カウンタ)を取得したい場合は、range()関数を使う。

for i in range(3):
    print(i)
# 0
# 1
# 2
source: for_range.py

range()range型のコンストラクタ。

print(range(3))
print(type(range(3)))
# range(0, 3)
# <class 'range'>
source: for_range.py

説明のため、list()でリストに変換して表示する。

range(stop)0 <= i < stopの連番を返す。

print(list(range(3)))
# [0, 1, 2]

print(list(range(6)))
# [0, 1, 2, 3, 4, 5]
source: for_range.py

0始まりではなく範囲を指定したい場合は、range(start, stop)のように2つの引数を指定する。

start <= i < stopの連番を返す。

print(list(range(10, 13)))
# [10, 11, 12]
source: for_range.py

さらに、1ずつではなく任意の増分を指定したい場合は、range(start, stop, step)のように3つの引数を指定する。

start <= i < stopの範囲でstepごとの整数値を返す。

print(list(range(0, 10, 3)))
# [0, 3, 6, 9]
source: for_range.py

stepには負の値を指定することも可能。

print(list(range(10, 0, -3)))
# [10, 7, 4, 1]
source: for_range.py

for文で使うと以下のようになる。

for i in range(10, 0, -3):
    print(i)
# 10
# 7
# 4
# 1
source: for_range.py

リストの要素とインデックス: enumerate()関数

リスト(配列)などのイテラブルオブジェクトの要素とインデックス(カウンタ)を同時に取得したい場合は、enumerate()関数を使う。

l = ['Alice', 'Bob', 'Charlie']

for name in l:
    print(name)
# Alice
# Bob
# Charlie

for i, name in enumerate(l):
    print(i, name)
# 0 Alice
# 1 Bob
# 2 Charlie

enumerate()関数の第二引数には開始値を指定できる。0始まりではなく任意の整数値から始められる。

for i, name in enumerate(l, 1):
    print(i, name)
# 1 Alice
# 2 Bob
# 3 Charlie

for i, name in enumerate(l, 42):
    print(i, name)
# 42 Alice
# 43 Bob
# 44 Charlie

enumerate()関数に増分stepを指定する引数はないが、以下のようにすると実現可能。

step = 3
for i, name in enumerate(l):
    print(i * step, name)
# 0 Alice
# 3 Bob
# 6 Charlie

複数リストの要素(複数変数): zip()関数

複数のイテラブルオブジェクト(リストなど)の要素を複数の変数としてまとめて取得したい場合は、zip()関数を使う。

names = ['Alice', 'Bob', 'Charlie']
ages = [24, 50, 18]

for name, age in zip(names, ages):
    print(name, age)
# Alice 24
# Bob 50
# Charlie 18

2変数に限らず、3つ以上のイテラブルオブジェクトをまとめることも可能。

points = [100, 85, 90]

for name, age, point in zip(names, ages, points):
    print(name, age, point)
# Alice 24 100
# Bob 50 85
# Charlie 18 90

例のように、zip()関数では複数のイテラブルオブジェクトの要素を同時に順番に取得できる。複数のイテラブルオブジェクトの要素のすべての組み合わせを取得したい場合は後述のitertools.product()関数を使う。

複数リストの要素とインデックス: enumerate(), zip()関数

複数のイテラブルオブジェクト(リストなど)の要素とインデックス(カウンタ)を同時に取得したい場合は、enumerate(), zip()関数を組み合わせて使う。

zip()関数の分の変数名を括弧()に囲む必要があるので注意。

names = ['Alice', 'Bob', 'Charlie']
ages = [24, 50, 18]

for i, (name, age) in enumerate(zip(names, ages)):
    print(i, name, age)
# 0 Alice 24
# 1 Bob 50
# 2 Charlie 18

逆順: reversed()関数

イテラブルオブジェクト(リストなど)の要素を逆順で取得したい場合は、reversed()関数を使う。

l = ['Alice', 'Bob', 'Charlie']

for name in reversed(l):
    print(name)
# Charlie
# Bob
# Alice

rangeオブジェクトも逆転可能。reversed()を使わずにstepに負の値を指定することもできる。

for i in reversed(range(3)):
    print(i)
# 2
# 1
# 0

for i in range(2, -1, -1):
    print(i)
# 2
# 1
# 0

enumerateオブジェクトは逆転できない。list()でリスト化すればOK。

# for i, name in reversed(enumerate(l)):
#     print(i, name)
# TypeError: 'enumerate' object is not reversible

for i, name in reversed(list(enumerate(l))):
    print(i, name)
# 2 Charlie
# 1 Bob
# 0 Alice

インデックス(カウンタ)は逆転したくない場合はenumerate()の中でreversed()を使う。

for i, name in enumerate(reversed(l)):
    print(i, name)
# 0 Charlie
# 1 Bob
# 2 Alice

zipオブジェクトも逆転できない。list()でリスト化すればOK。

l2 = [24, 50, 18]

# for name, age in reversed(zip(l, l2)):
#     print(name, age)
# TypeError: 'zip' object is not reversible

for name, age in reversed(list(zip(l, l2))):
    print(name, age)
# Charlie 18
# Bob 50
# Alice 24

多重ループ: itertools.product()関数

Pythonにおける多重ループは以下のように書ける。Pythonではインデントでブロックを表すので、さらにインデントを加えるだけ。

l1 = [1, 2, 3]
l2 = [10, 20, 30]

for i in l1:
    for j in l2:
        print(i, j)
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# 2 30
# 3 10
# 3 20
# 3 30

標準ライブラリitertoolsモジュールのitertools.product()を使うとforをネストすることなく多重ループと同様の結果が得られる。

import itertools

l1 = [1, 2, 3]
l2 = [10, 20, 30]

for i, j in itertools.product(l1, l2):
    print(i, j)
# 1 10
# 1 20
# 1 30
# 2 10
# 2 20
# 2 30
# 3 10
# 3 20
# 3 30

2つ以上のイテラブルオブジェクトを引数に指定することも可能。詳細は以下の記事を参照。

多重ループの内側のループから一気にbreakで抜け出す場合はitertools.product()を使うと簡単。以下の記事を参照。

辞書オブジェクトのforループ

辞書型dictのオブジェクトをforループで回すと、辞書のキーが取得できる。

d = {'key1': 1, 'key2': 2, 'key3': 3}

for k in d:
    print(k)
# key1
# key2
# key3

値あるいはキーと値のペアを取得したい場合は、values()メソッド、items()メソッドを使う。

for v in d.values():
    print(v)
# 1
# 2
# 3
for k, v in d.items():
    print(k, v)
# key1 1
# key2 2
# key3 3

詳細は以下の記事を参照。

リスト内包表記

リスト(配列)などのイテラブルオブジェクトの要素を処理して新たなリストを生成する場合は、for文よりもリスト内包表記を使うとシンプルに記述できる。

リスト内包表記は以下のように書く。

[ for 変数名 in イテラブルオブジェクト]

等価なfor文とともに例を示す。

squares = [i**2 for i in range(5)]
print(squares)
# [0, 1, 4, 9, 16]

squares = []
for i in range(5):
    squares.append(i**2)

print(squares)
# [0, 1, 4, 9, 16]

リスト内包表記を使うと、要素を処理するだけでなく、条件に応じて要素を抽出したりすることも可能なので覚えておいて損はない。

詳細は以下の記事を参照。

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事