プログラミング

Pythonのリスト内包表記とは?書き方をわかりやすく解説!(list comprehension:リスト生成:条件付き:ネスト:forループとの違いなど)

当サイトでは記事内に広告を含みます

Pythonを学んでいると「リスト内包表記」という書き方に出会うことがあります。forループを使った処理をよりシンプルかつPythonicに書けるリスト内包表記は、Pythonらしいコードを書くうえで欠かせない基本的な構文のひとつです。

リスト内包表記を使うとforループで書いていたリスト生成処理を1行にまとめられます。条件付きフィルタリング・変換処理・ネストしたループなど、様々なパターンに対応しており、コードの可読性と処理効率を同時に高められます。

この記事では、Pythonのリスト内包表記の基本的な書き方から、条件付きフィルタリング・ネスト・辞書内包表記・forループとの使い分けまで、サンプルコードとともにわかりやすく解説していきます。

Pythonのリスト内包表記はforループでのリスト生成を1行にまとめた書き方

それではまず、リスト内包表記の基本的な構造と書き方について解説していきます。

リスト内包表記の基本的な構文は「[式 for 変数 in イテラブル]」です。forループで書いていたリスト生成処理を角括弧の中に1行でまとめた形になっています。


# forループでリストを生成する従来の書き方
prices = [298, 498, 1200, 350, 420]
doubled_prices_loop = []
for price in prices:
    doubled_prices_loop.append(price * 2)

# リスト内包表記で書き直す
doubled_prices_comp = [price * 2 for price in prices]

print(doubled_prices_loop)
print(doubled_prices_comp)

# 出力結果:[596, 996, 2400, 700, 840]
# 出力結果:[596, 996, 2400, 700, 840]

forループと内包表記は同じ結果を返します。リスト内包表記の方がコードが短く、Pythonらしい書き方として広く使われています。

リスト内包表記はシンプルな変換・フィルタリング処理に適していますが、処理が複雑になる場合は無理に内包表記にまとめず、forループで書いた方がコードの可読性が保てます。「1行で書けるかどうか」よりも「読みやすいかどうか」を優先して使い分けましょう。

文字列リストの変換に使う基本パターン


# 文字列リストの変換
items = ["avocado", "salmon", "dragon_fruit", "gorilla_tea"]

# 大文字に変換
upper_items = [item.upper() for item in items]
print(upper_items)

# 文字数を取得
lengths = [len(item) for item in items]
print(lengths)

# アンダースコアをスペースに置換
formatted = [item.replace("_", " ") for item in items]
print(formatted)

# 出力結果:['AVOCADO', 'SALMON', 'DRAGON_FRUIT', 'GORILLA_TEA']
# 出力結果:[7, 6, 12, 10]
# 出力結果:['avocado', 'salmon', 'dragon fruit', 'gorilla tea']

文字列メソッドをリスト内包表記と組み合わせることで、リスト内の全要素に変換処理を一括適用できます。map()を使う書き方よりも直感的で読みやすいコードになります。

range()と組み合わせてリストを生成する


# range()と組み合わせた基本パターン
# 1〜10の2乗のリスト
squares = [n ** 2 for n in range(1, 11)]
print(squares)

# 1〜20の偶数のリスト
evens = [n for n in range(1, 21) if n % 2 == 0]
print(evens)

# 商品IDのリスト生成
product_ids = [f"ITEM_{i:04d}" for i in range(1, 6)]
print(product_ids)

# 出力結果:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 出力結果:[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
# 出力結果:['ITEM_0001', 'ITEM_0002', 'ITEM_0003', 'ITEM_0004', 'ITEM_0005']

range()との組み合わせは数列の生成・連番IDの作成・特定条件の数値抽出など幅広い場面で活用できます。

条件付きリスト内包表記の書き方

続いては、条件を付けて要素をフィルタリングしたり条件に応じて変換したりする内包表記の書き方を確認していきます。

リスト内包表記にif条件を加えることで、条件を満たす要素だけをフィルタリングしたり、条件に応じて異なる変換を適用したりする処理がシンプルに書けます。

if条件でフィルタリングする


# 条件付きリスト内包表記の基本
# [式 for 変数 in イテラブル if 条件]
products = [
    {"name": "アボカド", "price": 298, "category": "食品"},
    {"name": "キーボード", "price": 8500, "category": "PC周辺機器"},
    {"name": "サーモン", "price": 1200, "category": "食品"},
    {"name": "マウス", "price": 2000, "category": "PC周辺機器"},
    {"name": "ドラゴンフルーツ", "price": 498, "category": "食品"},
]

# 価格が500円以上の商品名を抽出
expensive = [p["name"] for p in products if p["price"] >= 500]
print(expensive)

# 食品カテゴリのみ抽出
foods = [p["name"] for p in products if p["category"] == "食品"]
print(foods)

# 出力結果:['キーボード', 'サーモン', 'マウス']
# 出力結果:['アボカド', 'サーモン', 'ドラゴンフルーツ']

末尾にif条件を追加するだけで、条件を満たす要素だけをリストに含めるフィルタリングが実現できます。filter()を使う書き方よりも直感的に読めます。

条件分岐(三項演算子)で値を変換する


# 三項演算子との組み合わせ
# [真の値 if 条件 else 偽の値 for 変数 in イテラブル]
prices = [298, 498, 1200, 350, 8500, 50]

# 500円以上なら"高"、未満なら"低"に分類
price_labels = ["高" if p >= 500 else "低" for p in prices]
print(price_labels)

# 在庫数を"あり"/"なし"に変換
stocks = [50, 0, 20, 0, 100, 0]
stock_status = ["在庫あり" if s > 0 else "在庫なし" for s in stocks]
print(stock_status)

# 出力結果:['低', '低', '高', '低', '高', '低']
# 出力結果:['在庫あり', '在庫なし', '在庫あり', '在庫なし', '在庫あり', '在庫なし']

三項演算子(値 if 条件 else 別の値)をリスト内包表記の式部分に使うことで、条件に応じた変換処理が1行で書けます。フィルタリングのif(末尾)と変換のif-else(先頭の式)の位置の違いに注意しましょう。

複数条件を組み合わせたフィルタリング


# 複数条件をandやorで組み合わせる
products = [
    ("アボカド", 298, 50),
    ("サーモン", 1200, 5),
    ("ドラゴンフルーツ", 498, 30),
    ("キーボード", 8500, 20),
    ("ネジ", 50, 500),
]

# 価格が100円以上かつ在庫が10個以上の商品名
result = [name for name, price, stock in products
          if price >= 100 and stock >= 10]
print(result)

# 価格が500円以上または在庫が100個以上の商品名
result2 = [name for name, price, stock in products
           if price >= 500 or stock >= 100]
print(result2)

# 出力結果:['アボカド', 'ドラゴンフルーツ', 'キーボード']
# 出力結果:['サーモン', 'キーボード', 'ネジ']

andやorで複数の条件を組み合わせることで、より詳細なフィルタリングが実現できます。条件が複雑な場合は改行してインデントを整えることでコードの可読性を維持できます。

ネストしたリスト内包表記の書き方

続いては、ネストしたforループをリスト内包表記で書く方法を確認していきます。

リスト内包表記はforを複数つなげることでネストしたループも1行で書けます。ただしネストが深くなると可読性が下がるため、2段階程度までの使用が目安です。

2次元リストをフラット化する


# ネストしたリストをフラットに展開する
nested = [
    ["アボカド", "サーモン"],
    ["キーボード", "マウス"],
    ["ネジ", "ボルト", "ワッシャー"],
]

# forループでのフラット化
flat_loop = []
for sublist in nested:
    for item in sublist:
        flat_loop.append(item)

# リスト内包表記でのフラット化
flat_comp = [item for sublist in nested for item in sublist]

print(flat_loop)
print(flat_comp)

# 出力結果:['アボカド', 'サーモン', 'キーボード', 'マウス', 'ネジ', 'ボルト', 'ワッシャー']
# 出力結果:['アボカド', 'サーモン', 'キーボード', 'マウス', 'ネジ', 'ボルト', 'ワッシャー']

ネストした内包表記はforを左から右に読む順番が、forループを外側から内側に書く順番と対応しています。「外側のforが先、内側のforが後」と覚えておきましょう。

組み合わせのリストを生成する


# 2つのリストの全組み合わせを生成する
categories = ["食品", "部品"]
items = ["アボカド", "ネジ", "サーモン"]

combinations = [(cat, item) for cat in categories for item in items]
for combo in combinations:
    print(combo)

# 出力結果:('食品', 'アボカド')
# 出力結果:('食品', 'ネジ')
# 出力結果:('食品', 'サーモン')
# 出力結果:('部品', 'アボカド')
# 出力結果:('部品', 'ネジ')
# 出力結果:('部品', 'サーモン')

2つのリストの全組み合わせを生成するパターンはテストデータの作成やカテゴリとアイテムのマッピング生成などに活用できます。

2次元リスト(行列)を生成する


# 2次元リスト(行列)をリスト内包表記で生成する
rows = 3
cols = 4

# 0で埋めた行列
matrix = [[0 for _ in range(cols)] for _ in range(rows)]
for row in matrix:
    print(row)

print()

# 行×列の値を持つ行列
value_matrix = [[r * cols + c for c in range(cols)] for r in range(rows)]
for row in value_matrix:
    print(row)

# 出力結果:[0, 0, 0, 0]
# 出力結果:[0, 0, 0, 0]
# 出力結果:[0, 0, 0, 0]
# 出力結果:
# 出力結果:[0, 1, 2, 3]
# 出力結果:[4, 5, 6, 7]
# 出力結果:[8, 9, 10, 11]

外側の内包表記が行、内側の内包表記が列を表すパターンです。2次元リストの初期化や行列データの生成に使えます。

辞書内包表記・集合内包表記との比較

続いては、内包表記の仲間である辞書内包表記と集合内包表記の書き方を確認していきます。

内包表記の構文はリストだけでなく辞書や集合にも適用できます。括弧の種類を変えるだけで辞書内包表記・集合内包表記が書けます。

辞書内包表記の基本


# 辞書内包表記:{キー: 値 for 変数 in イテラブル}
items = ["アボカド", "サーモン", "ドラゴンフルーツ", "キーボード"]
prices = [298, 1200, 498, 8500]

# 2つのリストからキーと値の辞書を生成
price_dict = {item: price for item, price in zip(items, prices)}
print(price_dict)

# 既存の辞書から条件でフィルタリング
expensive_dict = {k: v for k, v in price_dict.items() if v >= 500}
print(expensive_dict)

# 出力結果:{'アボカド': 298, 'サーモン': 1200, 'ドラゴンフルーツ': 498, 'キーボード': 8500}
# 出力結果:{'サーモン': 1200, 'キーボード': 8500}

辞書内包表記は波括弧{}を使い、「キー: 値」の形式で書きます。zip()との組み合わせで2つのリストを辞書に変換するパターンや、既存の辞書をフィルタリングするパターンが実務でよく使われます。

集合内包表記と各内包表記の比較


data = ["アボカド", "サーモン", "アボカド", "ゴリラ茶", "サーモン"]

# リスト内包表記(重複あり)
list_result = [item for item in data]

# 集合内包表記(重複なし)
set_result = {item for item in data}

# 辞書内包表記(文字数をマッピング)
dict_result = {item: len(item) for item in data}

print(f"リスト:{list_result}")
print(f"集合:{set_result}")
print(f"辞書:{dict_result}")

# 出力結果:リスト:['アボカド', 'サーモン', 'アボカド', 'ゴリラ茶', 'サーモン']
# 出力結果:集合:{'アボカド', 'サーモン', 'ゴリラ茶'}
# 出力結果:辞書:{'アボカド': 4, 'サーモン': 4, 'ゴリラ茶': 4}

[]はリスト、{}はキーのみなら集合・キー:値なら辞書、()はジェネレータ式になります。用途に応じた括弧を使い分けましょう。

まとめ

この記事では、Pythonのリスト内包表記の書き方について、基本的な構文からフィルタリング・三項演算子・ネスト・辞書内包表記・集合内包表記まで幅広く解説しました。

リスト内包表記の基本構文は「[式 for 変数 in イテラブル]」です。末尾にif条件を付けるとフィルタリング、式部分に三項演算子を使うと条件分岐変換が実現できます。forを複数つなげるとネストしたループが表現でき、波括弧{}にするだけで辞書・集合内包表記にも応用できます。

シンプルな変換・フィルタリング処理にはリスト内包表記を積極的に使い、処理が複雑になる場合はforループで書く使い分けが大切です。ぜひ実際のコードで積極的に活用してみてください。

リスト内包表記はforループとほぼ同じ処理を行いますが、Pythonの内部実装の最適化により一般的にforループよりも高速に動作します。ただし処理が複雑でネストが深い場合は無理に内包表記にせず、読みやすさを優先してforループで書きましょう。コードは「書く人」だけでなく「読む人」のためにも書くものです。