リストの要素のうち、ある条件を満たした要素のみ抽出(スクリーニング)したい場面があると思います。そんな時は、例えばforループでひとつひとつ要素をチェックして別のリストに追加していくとか、様々な方法があります。
filter()はその中の一つで、この機能をとても簡単に書くことができます。また逆に、条件を満たさない要素のみを抽出したい場合は、itertools.filterfalse()も便利です。
どちらもPythonの組込み関数なので新たに何かをインストールする必要もありません。
今回は、こんなfiliter関数の使い方についてまとめます。
確認した環境
- Ubuntu16.04LTS
- Python3.7.2@Anaconda
filter()関数の使い方
使い方は下記のとおり。
filter(function, iterable)
iterableで指定したイテラブル(例えばリスト)の各要素それぞれについて、functionで設定した条件を満たした要素だけを抽出して新たなイテレータを生成します。
返り値はジェネレータイテレータとなり、この関数はジェネレータ式
(item for item in iterable if function(item))
と同等です。
以下に例を示します。
まず、条件式funcを作成します。
# 5より大きい数値の場合はTrue、そうでない場合はFalseを返す関数
>>> def func(a):
... return True if a > 5 else False
次に、作成した条件に合致した要素を抽出してみます。
# 第2引数に渡したリストのうち、条件funcに合致した要素を抽出する例
>>> gen = filter(func, [10, 5, 7, 3, 9])
# 返り値はジェネレータのオブジェクトとなりますので、このままでは要素は見れません。
>>> gen
<filter object at 0x7fefb76110b8>
# リスト型にするにはlist()を使います。
>>> list(gen)
[10, 7, 9]
尚、上記はlambda式を使うともう少し簡単に書けます。
>>> gen = filter(lambda x: x > 5, [10, 5, 7, 3, 9])
>>> list(gen)
[10, 7, 9]
もうひとつ、ジェネレータ式でも同様の機能を実現できるので、下記に示します。
※このくらいだったら素直にリスト内包表記でも良い気がしますが。。。
>>> gen = (n for n in [10, 5, 7, 3, 9] if n > 5)
>>> list(gen)
[10, 7, 9]
尚、functionがNoneの場合は、iterableのFalseの要素が全て除去されます。
すなわち、 (item for item in iterable if item) と同等です。
>>> gen = filter(None, [10, 5, 0, 3, 9])
>>> list(gen)
[10, 5, 3, 9]
# 下記のジェネレータ式と同等です
>>> gen = (n for n in [10, 5, 0, 3, 9] if n)
>>> list(gen)
[10, 5, 3, 9]
<参考>公式リファレンス
https://docs.python.org/ja/3.7/library/functions.html#filter
itertools.filterfalse()関数
itertoolsモジュールのメソッドの一つです。
iterable の各要素をpredicateで評価した結果、偽の要素のみを返します。filter()関数と逆です。
使い方は以下です。
itertools.filterfalse(predicate, iterable)
返り値がジェネレータとなる点などはfilter()関数と同じです。
>>> import itertools
# 数値が5より大きくないものを抽出します・
>>> gen = itertools.filterfalse(lambda x: x > 5, [10, 5, 7, 3, 9])
# 返り値はジェネレータのオブジェクトとなりますので、このままでは要素は見れません。
>>> gen
<itertools.filterfalse object at 0x7fefb76110f0>
# リスト型にするには、list()を使います。
>>> list(gen)
[5, 3]
また、これもfilter()関数と同様ですが、predicate が None の場合、Trueの要素が除去されます(=偽の要素だけを返します。)
# 引数に渡したリストのうち、偽の要素のみを抽出
>>> gen = itertools.filterfalse(None, [10, 5, 0, 3, 9])
>>> list(gen)
[0]
※ 0は偽です。参考記事はこちら。
<参考>公式リファレンス
https://docs.python.org/ja/3/library/itertools.html?highlight=filterfalse#itertools.filterfalse
まとめ
今回はfilter()関数の使い方についてまとめました。