Pythonの大きな魅力の一つに、シンプルで読みやすいコードが書ける点が挙げられます。
その象徴的な機能が「内包表記」です。
特にリスト内包表記は、ループ処理を使って新しいリストを生成する際に、for
ループを一行で簡潔に記述できるため、多くのPythonプログラマーに愛用されています。
しかし、この内包表記にif
文による条件分岐を組み合わせようとすると、多くの初学者が混乱に陥ります。
「条件に合うものだけを抽出したい」場合と、「条件によって値を振り分けたい(if-else
)」場合とで、if
の書き方や記述する場所が全く異なるからです。
そこでこの記事では、if
を使ったフィルタリングからif-else
(三項演算子)の応用、さらには複数条件の組み合わせまで、豊富なサンプルコードと図解を交えて、初心者でもわかるように徹底的に解説します。
【本記事の信頼性】
- 執筆者は元エンジニア
- 大手プログラミングスクールのWebディレクター兼ライターを経験
- 自らも地元密着型のプログラミングスクールを運営
受講生から評判の良いプログラミングスクール
スクール |
特徴 |
受講料金 |
大手比較サイトで4年連続人気NO.1!受講生からの評判も非常に高く、Web系のエンジニアを目指すならRUNTEQ一択。 | 550,000円(給付金適用あり) | |
月単価80万円以上の現役エンジニア講師による指導!一度入会すればサポートは半永久的。 | 498,000円 | |
格安で質の高いWeb制作スキルを習得したい人におすすめ!業界最安級の料金でありながら、コミュニティやサポートが充実。 | 129,800円~ | |
完全無料でプログラミングが学べる貴重なスクール!最短1ヶ月で卒業可能。ゼロスク運営会社への就職もできる。 | 無料 | |
長期間に渡って学習し、希少人材を目指す人に最適なスクール!受講料は高いものの、高収入を得られる人材を目指せる。 | 96~132万円 |
【結論】ifを使った内包表記チートシート
まず最初に、この記事の結論となる最も重要な2パターンの構文を早見表(チートシート)で示します。
多くの場合、あなたの疑問はこの表で解決するはずです。
目的 | 通常のforループ | リスト内包表記 |
---|---|---|
条件に合う要素だけを抽出 (ifのみ) | for item in list: <br> if condition: <br> ... |
[式 for item in list if condition] |
条件で値を振り分ける (if-else) | for item in list: <br> if condition: <br> ... <br> else: <br> ... |
[真の式 if condition else 偽の式 for item in list] |
この2つの大きな違いは、if
だけの場合はfor
の後ろに書き、if-else
の場合はfor
の前に書くという点です。
なぜこのような違いが生まれるのか、これから順を追って解説していきます。
リスト内包表記の基本
if
の話に入る前に、まずは最もシンプルなリスト内包表記の形を復習しておきます。
リスト内包表記は、既存のリストやシーケンスから新しいリストを効率的に作成するための構文です。
基本形は以下の通りです。
[式 for 変数 in イテラブルオブジェクト]
例えば、0から9までの数値を2倍した新しいリストを作成する場合、通常のfor
ループではこう書きます。
numbers = []
for i in range(10):
numbers.append(i * 2)
print(numbers)
実行結果は以下の通りです。
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
これがリスト内包表記を使うと、わずか一行で書けてしまいます。
(実行結果は上記と同じです)
numbers = [i * 2 for i in range(10)]
print(numbers)
この基本形を土台に、if
を追加していきます。
パターン1:ifで条件に合う要素を絞り込む(フィルタリング)
最初のパターンは、条件式を満たす要素だけを新しいリストに含める、最も直感的な使い方です。
これは「フィルタリング」と呼ばれます。
構文は以下の通りです。
[式 for 変数 in イテラブルオブジェクト if 条件式]
この構文は、for
ループで要素を一つずつ取り出し、その要素がif
の条件を満たす場合のみ、先頭の「式」を評価して新しいリストに加える、という流れになります。
for
ループの記述のすぐ後ろにif
文をそのまま繋げるイメージです。
【コード例:0から9のうち、偶数だけを抽出してリストにする】
まずは比較のため、通常のfor
ループで書いてみましょう。
even_numbers = []
for i in range(10):
if i % 2 == 0: # 偶数かどうかの条件
even_numbers.append(i)
print(even_numbers)
実行結果は以下の通りです。
[0, 2, 4, 6, 8]
次に、これをリスト内包表記で書き換えます。
for i in range(10)
の後ろにif i % 2 == 0
を繋げるだけです。
(実行結果は上記と同じです)
even_numbers = [i for i in range(10) if i % 2 == 0]
print(even_numbers)
ご覧の通り、コードが非常に簡潔になりました。
このように、条件に合う要素だけを選び出す場合は、for
の後ろにif
を記述すると覚えてください。
パターン2:if-elseで要素を振り分ける(三項演算子)
次が、多くの学習者がつまずくif-else
のパターンです。
このパターンでは、条件を満たすかどうかでリストに入れる値を振り分けます。
if-else
のパターンの構文は以下の通りです。
[真の場合の式 if 条件式 else 偽の場合の式 for 変数 in イテラブルオブジェクト]
if
のみの場合と比べて、if-else
のブロックがfor
の前に来ていることがわかるはずです。
これは、この部分が三項演算子(Conditional Expressions)と呼ばれる、それ自体がひとつの「式」として扱われるものだからです。
if
のみの構文:for
ループの一部として、要素をフィルタリングする役割。if-else
の構文: リストの要素となる値を生成する「式」そのもの。
リスト内包表記の基本形[式 for ...]
の、「式」の部分に三項演算子真の場合の式 if 条件式 else 偽の場合の式
がそのまま入っていると考えると、この語順を理解しやすくなります。
【コード例:0から9の数値について、偶数なら”even”、奇数なら”odd”という文字列のリストを作成する】
通常のfor
ループでは以下のようになります。
result = []
for i in range(10):
if i % 2 == 0:
result.append("even")
else:
result.append("odd")
print(result)
実行結果は以下の通りです。
['even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd', 'even', 'odd']
これをリスト内包表記で書くと、for
の前に三項演算子を記述することになります。
(実行結果は上記と同じです)
result = ["even" if i % 2 == 0 else "odd" for i in range(10)]
print(result)
この違いを明確に理解することが、内包表記を使いこなす上での最大の鍵となります。
【応用編】さらに複雑な内包表記
基本の2パターンをマスターすれば、さらに複雑な条件にも対応できます。
複数のif条件を組み合わせる
if
によるフィルタリングは複数連結できます。
これはand
条件と同じ意味になります。
例:0から29のうち、「3の倍数」かつ「5の倍数」である数を抽出
# and を使う方法
multiples = [i for i in range(30) if i % 3 == 0 and i % 5 == 0]
print(multiples)
# if を連結する方法
multiples_chained = [i for i in range(30) if i % 3 == 0 if i % 5 == 0]
print(multiples_chained)
実行結果は以下の通りです。
[0, 15]
[0, 15]
どちらの書き方でも同じ結果が得られますが、一般的にはand
を使う方が読みやすいでしょう。
ネストしたforループとifを組み合わせる
for
ループをネスト(入れ子に)することも可能です。例えば、2次元リストを1次元に平坦化しつつ、条件でフィルタリングできます。
例:2次元リストから、5より大きい要素だけを抽出して1次元リストにする
matrix = [
[1, 6, 3],
[8, 2, 10],
[4, 9, 7]
]
flattened = [num for row in matrix for num in row if num > 5]
print(flattened)
実行結果は以下の通りです。
[6, 8, 10, 9, 7]
for row in matrix
が外側のループ、for num in row
が内側のループに対応します。
for
を記述する順番は、通常のfor
ループのネストと同じ順序になることを覚えておきましょう。
辞書内包表記・集合内包表記でのif
このif
の考え方は、リストだけでなく辞書や集合の内包表記でも全く同じように使えます。
# 辞書内包表記:キーが奇数の要素だけを抽出
base_dict = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
odd_dict = {k: v for k, v in base_dict.items() if v % 2 != 0}
print(odd_dict) # {'a': 1, 'c': 3}
# 集合内包表記:10未満の3の倍数を抽出
numbers_set = {i for i in range(10) if i % 3 == 0}
print(numbers_set) # {0, 3, 6, 9}
内包表記の注意点:可読性とのバランス
内包表記は非常に強力ですが、万能薬ではありません。
何でもかんでも一行で書こうとすると、かえって可読性(コードの読みやすさ)を著しく損なう可能性があります。
■悪い例:過度に複雑な内包表記
# 非常に読みにくい...
result = [f"{x}-{y}" for x in range(3) if x % 2 == 0 for y in range(3) if y > 0]
このコードが何をしているか、一目で理解するのは困難です。
このような場合は、無理に内包表記を使わず、素直に通常のfor
ループで書くべきでしょう。
■書き直した良い例
result = []
for x in range(3):
if x % 2 == 0:
for y in range(3):
if y > 0:
result.append(f"{x}-{y}")
こちらのコードの方が、処理の流れが追いやすく、誰にとっても理解しやすいはずです。
「処理が複雑になりすぎたら、for
ループに戻る」という判断基準を持つことが、良いコードを書く上で重要です。
まとめ
今回は、Pythonの内包表記でif
文を扱う方法について、その核心的な違いから応用までを詳しく解説しました。
なお、Pythonを体系的に学んだり、Pythonのスキルを高めたりするためには、プログラミングスクールを利用するのも有効です。
細かな疑問がすぐに解決するだけでなく、現役エンジニアが「質の高いポートフォリオ」を作成するための手助けをしてくれたり、エンジニア就職・転職のコツを教えてくれたりするなど、様々なメリットがありますので、独学に疲れた方は検討してみてはいかがでしょうか。