Pythonのリスト内包表記まとめ

284, 2021-07-06

目次

Pythonのリスト内包表記まとめ

Pythonには内包表記と呼ばれる独特なループ処理があります。
ちょっとしたコードを一行にすることができるので、細かいところで役に立つ記法です。

結論から言うとリスト内包表記は↓のように使います。

# ↓のようなfor文が
lis = []
for i in range(4):
    lis.append(i)
print(lis)
# [0, 1, 2, 3]

# 内包表を使うと↓のように書ける
lis = [i for i in range(4)]
print(lis)
# [0, 1, 2, 3]

この記事では具体的にリスト内包表記について↓を見ていきます。

  • リストと内包表記の書き方

  • if文との連携

  • 三項演算子との連携

  • リスト内包表記のネスト

  • zipとリスト内包表記

  • enumerateとリスト内包表記

  • タプルと内包表記の書き方

  • 辞書と内包表記の書き方

  • 集合と集合表記の書き方

  • ジェネレータ式

関連記事
for文とリストの賢い使い方4つ【Python】
Pythonでリスト(配列)に普通に要素を追加する方法
Pythonのrangeのイマドキな使い方

リストと内包表記の書き方

リスト内包表記は↓のように書きます。

[要素 for 要素 in オブジェクト]

↑の場合、オブジェクト(イテレーション可能なオブジェクト)が回されて要素が取り出され、その要素がリストに追加されていきます。
具体的なコードは↓になります。

lis = [i for i in range(4)]
print(lis)
# [0, 1, 2, 3]

↑の場合、rage(4)がイテレーション可能なオブジェクトです。これは数列を生成します。
その生成された数がiです。0から始まるiが取り出されてリストに保存されます。
↑のコードは↓のコードと等価です。

lis = []
for i in range(4):
    lis.append(i)
print(lis)
# [0, 1, 2, 3]

if文との連携

内包表記にはif文を書くことができます。
たとえば0から4より下まで数列を生成して、その生成された数を偶数のみ保存したい場合は↓のようにします。

# 偶数のみ保存
lis = [i for i in range(4) if i % 2 == 0]
print(lis)
# [0, 2]

奇数のみ保存するには↓のようにします。

# 偶数のみ保存
lis = [i for i in range(4) if i % 2 != 0]
print(lis)
# [1, 3]

なんか変わった記法だね

はい。内包表記の関連の記法は変わっています。
ですので慣れが必要です。

習うより慣れろ、ね

関連記事
Pythonのif文の書き方【条件分岐】 - なるぽのブログ

三項演算子との連携

リスト内包表記で三項演算子を使いたい場合は↓のようにします。

# 偶数以外は-1で保存
lis = [i if i % 2 == 0 else -1 for i in range(4)]
print(lis)
# [0, -1, 2, -1]

↑の場合はiの値が偶数ならそのまま保存し、奇数なら-1を保存しています。

リスト内包表記のネスト

リスト内包表記はネストすることができます。
たとえば行列を作りたい場合は↓のようにします。

matrix = [[i for i in range(4)] for i in range(2)]
print(matrix)
# [[0, 1, 2, 3], [0, 1, 2, 3]]

細かく見てみましょう。
まず↑の↓の部分は

[i for i in range(4)]

[0, 1, 2, 3]というような行列の列を生成します。
それから↑の↓の部分は

[内側の内包表記 for i in range(2)]

行列の行を生成しています。
↑の場合、内側の内包表記を2回繰り返すという意味になります。

zipとリスト内包表記

zip()とリスト内包表記の組み合わせは↓のように書きます。

lis1 = ['cat', 'dog', 'bird', 'pig']
lis2 = [0, 1, 2, 3]
lis3 = [kv for kv in zip(lis1, lis2)]
print(lis3)
# [('cat', 0), ('dog', 1), ('bird', 2), ('pig', 3)]

あるいは↓のようにキーと値を分解して再構築することも出来ます。

lis1 = ['cat', 'dog', 'bird', 'pig']
lis2 = [0, 1, 2, 3]
lis3 = [(v, k) for k, v in zip(lis1, lis2)]
print(lis3)
# [(0, 'cat'), (1, 'dog'), (2, 'bird'), (3, 'pig')]

関連記事
Pythonのzipの使い方: 複数のイテラブルからイテレーターを作る

enumerateとリスト内包表記

enumerate()とリスト内包表記の組み合わせは↓のように書きます。

lis1 = ['cat', 'dog', 'bird', 'pig']
lis2 = [(i, v) for i, v in enumerate(lis1)]
print(lis2)
# [(0, 'cat'), (1, 'dog'), (2, 'bird'), (3, 'pig')]

↑はivをそのままの順序でタプルにして保存してますが、順序を逆にしたり添え字だけ保存したりなど自由に書くことができます。

関連記事
Pythonのenumerate()を使いこなす

タプルと内包表記の書き方

内包表記の外側をカッコにすればタプルが生成されるのか? と思ったみなさん、残念なお知らせです。
タプルの場合は↓のように書きます。

tup = tuple(i for i in range(4))
print(tup)
# (0, 1, 2, 3)

実はカッコはジェネレータ式で予約されています。
そのためタプルを生成したい場合は↑のように書きます。
↑の式も実はジェネレータ式で生成したジェネレータをtuple()に渡しているだけです。

辞書と内包表記の書き方

内包表記で辞書を生成するには↓のようにします。

dic = {str(i): i**2 for i in range(4)}
print(dic)
# {'0': 0, '1': 1, '2': 4, '3': 9}

↓のようにキーと値を指定します。

{キー: 値 for 要素 in オブジェクト}
{キー: 値 for キー, 値 in オブジェクト}

たとえば文字列のリストを内包表記で回して、その文字列をキー、文字列の長さを値にしたい場合は↓のようにします。

lis = ['cat', 'horse', 'bird']
dic = {s: len(s) for s in lis}
print(dic)
# {'cat': 3, 'horse': 5, 'bird': 4}

関連記事
Pythonで辞書(dict)にキーと値を追加する方法
Pythonのdict(辞書)の使い方

集合と集合表記の書き方

集合を内包表記で生成したい場合は↓のようにします。

s = {i for i in range(4)}
print(s)
# {0, 1, 2, 3}

ジェネレータ式

ジェネレータ式は↓のように書きます。

g = (i for i in range(4))
print(g)
# <generator object <genexpr> at 0x1234>

ジェネレータ式は内包表記のノリでジェネレータを生成できる記法です。
↑のように返り値はジェネレータになります。
つまり↓のようにnext()などに渡すことができます。

g = (i for i in range(4))
print(next(g))  # 0
print(next(g))  # 1
print(next(g))  # 2
print(next(g))  # 3

普通のジェネレータの生成と見比べてみましょう。

def gen():
    for i in range(4):
        yield i

g = gen()
print(g)
# <generator object gen at 0x1234>

↑のコードを見ると、ジェネレータ式の省エネ具合が良くわかるかと思います。楽でいいですね。

おわりに

今回はPythonのリスト内包表記について見てみました。
内包表記は覚えておくとコードの行数を減らすことができます。

猫はかわいさを内包している

(たしかに。。)