プログラミング
記事内に商品プロモーションを含む場合があります

簡潔にリストを生成できる!Pythonの内包表記について解説

tadanori

この記事では、Pythonの内法表記について解説します。内包表記を利用すると、短い記述でリストを生成することが可能です。

内法表記とは

Pythonでは、内包表記を利用することで、新しいリストをシンプルな表記で生成することができます。また、リストだけでなく集合(set)や辞書(dict)も簡潔に生成することが可能です。

Python以外の言語を使っている方には馴染みが少ないかもしれませんが、慣れれば簡単ですし、コードの可読性も高くなります。

それほどたくさんの言語を使ったことはありませんが、RubyやJavaScriptも内包表記に近い記述を行うことが可能です。

内包表記を利用したリストの生成

基本的な使い方

連番値のリスト生成する

基本的な使い方は、forを使ってリストを生成するものです。下記の例は、連番のリストを生成します。

a = [x for x in range(10)]
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

要素数nのリストを特定値で初期化

連番だけではなく、特定の値のn個生成すること可能です。リストの初期化で多用します。

a = [-1 for _ in range(10)]
# [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1]

条件付きの内法表記

内法表記では条件式と組み合わせた生成を行うことも可能です。

if文を用いた条件式で値を設定

偶数の場合だけリストに追加する例です。forの後ろに条件を記述します。

a = [x for x in range(10) if x%2 == 0]
# [0, 2, 4, 6, 8]

奇数の場合は0、偶数の場合は1をリストに追加する例です。forの前に条件を記述します。

a = [1 if x%2 == 0 else 0 for x in range(10)]
# [1, 0, 1, 0, 1, 0, 1, 0, 1, 0]

複雑な式

式を用いてリストを作成

式を利用してリストの値を生成することも可能です。下記の例は一次式$2x + 3$で値を生成しています。

a = [2 * x + 3 for x in range(10)]
# [3, 5, 7, 9, 11, 13, 15, 17, 19, 21]

関数を用いてリストを作成

関数を利用することも可能です。下記は関数を利用して値を生成する例です。

def f(a) :
  return a**2

a = [f(x) for x in range(10)]
# [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

応用例

逆引き辞書を作成

辞書の生成にも内包表記を利用することが可能です。

dic = {x : x**2 for x in range(10)}
# {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}

内包表記を利用することで、逆引きの辞書を作成することも可能です。

reverse_dic = {dic[v] : v for v in dic}
# {0: 0, 1: 1, 4: 2, 9: 3, 16: 4, 25: 5, 36: 6, 49: 7, 64: 8, 81: 9}

逆引き辞書の作成は、結構いろいろな時に使いますので覚えておくと良いです。

2次元配列(2次元リスト)の生成

2次元や3次元のリストを作成することも可能です。下記は、2次元のリストを0に初期化する例です。

a = [[0 for _ in range(3)] for _ in range(5)]
# [[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]

条件に一致する値だけ抜き出す

3の倍数だけ抜き出してリストにする

別のリストから、特定条件に一致する列だけ抜き出して新しいリストを生成することもできます。下記はリストaから3の倍数の値だけ抜き出してリストbを作成しています。

import random
a = [random.randint(1,1000) for _ in range(10)]
# [632, 252, 271, 303, 905, 784, 153, 722, 392, 331]
b = [e for e in a if e%3 == 0]
# [252, 303, 153]

速度評価

内法表記の利点は、シンプルに書けることだけではありません。

ループで記述するのと比較して、高速である点もメリットの1つです。

ここでは、実際にどの程度高速なのかを測定した結果を紹介します。

プログラム

評価に利用したプログラムは以下になります。

100万個の要素を持つリストを、内包表現と、ループの2種類の方法で生成しています。

プログラムでは生成処理をloop=100回繰り返し、処理時間を計測しました。

import time

n = 1000000
loop = 100

# 内包表記を使ったリスト生成
start_time = time.time()
for _ in range(loop):
    list_comp = [x for x in range(n)]
end_time = time.time()
comp_time = end_time - start_time

# ループを使ったリスト生成
start_time = time.time()
for _ in range(loop):
    list_loop = []
    for x in range(n):
        list_loop.append(x)
end_time = time.time()
loop_time = end_time - start_time

print(f"内包表記の実行時間: {comp_time}秒")
print(f"ループの実行時間: {loop_time}秒")

結果

結果は以下のようになります。実験に利用した環境はPython3.11.4(Macbook Air m2)です。

内包表記の実行時間: 1.4358179569244385秒
ループの実行時間: 2.668544054031372秒

約1.9倍ほど、内法表記の方が高速という結果になりました。

このように、内包表記を利用することでリストの生成を高速化することが可能です。

書き方だけで約2倍速くなるというのは、結構大きな差です。

まとめ

Pythonの内法表記の記述方法と、応用例、速度についてまとめました。あまり馴染みがない人もいるかもしれませんが、記述がシンプルになることと、速度面で有利なことを考えると、積極的に使っていくと良いかしれません。

個人的には、あまり複雑な内包表現は可読性の面から避けるべきだと思います。内包表現とループのどちらが読みやすいかも考えながらうまく使っていくと良いと思います。

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

記事URLをコピーしました