filter で要素を絞り込む

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

filter で要素を絞り込む とは

filter 関数で条件に合う要素だけを残す方法を学びます。本レッスンでは、filter で要素を絞り込む の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

filter で要素を絞り込む

前のレッスンで学んだ map が「全要素を変換する」役割なら、filter は「条件に合う要素だけ残す」役割を担う高階関数です。リストから偶数だけ取り出す、5 文字以上の単語だけ残す、None でない要素だけ集める、といった作業に最適です。

mapfilter は兄弟のような関係です。前者は要素の 形を変える、後者は要素を 選別する。両方を組み合わせるとデータ整形の幅がぐっと広がります。

文法

filter(関数, イテラブル) という形で書きます。渡す関数は True / False を返す述語 (predicate) 関数です。

Python

nums = [1, 2, 3, 4, 5, 6] result = filter(lambda x: x % 2 == 0, nums) print(list(result))

x % 2 == 0True の要素 (偶数) だけが残ります。出力は [2, 4, 6] です。filter の戻り値も map と同じくイテレータなので、list() で囲んで使うのが基本です。

述語関数とは

filter に渡す関数は、必ず真偽値 (True / False) を返す必要があります。

Python

def is_positive(x): return x > 0 result = list(filter(is_positive, [-2, -1, 0, 1, 2])) print(result)

結果は [1, 2] です。def で関数を作って渡しても、lambda でその場で書いても、どちらでも構いません。

for ループとの比較

for ループで同じことをすると次の通りです。

Python

result = [] for n in nums: if n % 2 == 0: result.append(n)

3 行が filter なら 1 行で済みます。コードを読む側にとっても「条件で絞り込んでいる」という意図がすぐに伝わります。

「if と append が組み合わさったら filter かも」とアンテナを張っておくと、自然と高階関数を活用できるようになります。

filter vs リスト内包表記

リスト内包表記でも同じことができます。

Python

result = [x for x in nums if x % 2 == 0]

Python ではこの書き方の方が一般的です。filter既存の述語関数を再利用したいとき や、関数型プログラミング寄りのスタイル を採用したいときに使うのが良い選択です。

Python

names = ["", "太郎", "", "花子", None] result = list(filter(None, names)) print(result)

filter(None, ...) という特殊な書き方も使えます。これは truthy (真と見なせる) 値だけを残す書き方です。空文字や None が排除され、結果は ["太郎", "花子"] になります。

動きを追ってみる

filter の処理を図にします。

diagram (will load when visible)

要素ごとに「合格」「不合格」を判定して、合格したものだけ新しいリストに集めます。map と違って 要素の中身は変えない のがポイントです。

map と filter の組み合わせ

データ処理では mapfilter を組み合わせて使うことが多いです。

Python

nums = [1, 2, 3, 4, 5] even_squared = list(map(lambda x: x * x, filter(lambda x: x % 2 == 0, nums))) print(even_squared)

偶数だけ取り出して 2 乗 する処理です。filter[2, 4] に絞り込み、map[4, 16] に変換しています。

関数を パイプライン のように繋いでデータを流す書き方は、関数型プログラミングの面白さの 1 つです。

よくある間違い

  • 述語関数が True / False 以外を返してしまう
  • filter の戻り値をリストとして使おうとして list() で囲み忘れる
  • filter を 2 回回そうとすると 2 回目は空 (イテレータが消費済み)

Python

f = filter(lambda x: x > 0, [-1, 1, 2]) print(list(f)) print(list(f))

2 回目は [] になります。filter は使い捨てのイテレータです。何度も使うなら最初に list に変換しておきましょう。

やってみよう

それでは、整数のリスト arr を受け取って、偶数だけを残した新しいリストを返す関数 keep_evenfilterlambda で書いてみましょう。x % 2 == 0 が偶数判定の条件です。テストでは keep_even([1, 2, 3, 4]) のような形で呼び出されます。

よくある質問

Q. filter と find の違いは?

A. filter は条件を満たす要素を全部集めて配列で返し、find は最初に見つかった 1 件だけ返します。1 件だけ欲しいなら find の方が短絡評価で速く、空のとき undefined(Python の next は StopIteration)になる点に注意してください。

Q. filter の戻り値が空配列のときの扱いは?

A. JS の filter は常に配列を返すため、空でも .length で安全にチェックできます。Python の filter はイテレータを返すので list() で囲んでから使うか、内包表記 [x for x in items if cond] の方が分かりやすいことが多いです。

Q. filter と map をチェーンしても性能は大丈夫ですか?

A. 通常規模なら問題ありません。配列を 2 周することになるため、要素数が数百万を超える場合だけ reduce にまとめるか、JS なら array.reduce で 1 周にすることを検討してください。可読性は filter→map のチェーンが分かりやすいです。

次のレッスン

次は reduce で畳み込む で、filter 関数で条件に合う要素だけを残す方法を学びます を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. filter の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. filter とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. filter と lambda を組み合わせて使う
  2. x % 2 == 0 で偶数を判定する
  3. list で囲んで結果をリストとして返す

入出力例

test-cases.txt

keep_even([1,2,3,4])[2,4] keep_even([1,3,5])[] keep_even([2,4,6])[2,4,6] keep_even([])[] keep_even([0,-2,-3,-4])[0,-2,-4]

ヒント

main.py
main.py
学習モード

メモ

filter で要素を絞り込む

⌘S で保存