filter()

filter()

filter()

 filter() はリストやタプルなどから、特定の条件を満たす要素を抽出 (フィルタリング) する関数です。filter() 関数の正式な書式は

filter(function or None, iterable)

ですが、実用上は

filter(関数, リスト)

と覚えておけば十分です。関数は何でもよいというわけでなく、True または False を返すように定義されていなければなりません。簡単な例として、50 以上の数値を渡すと True を返す関数 geq_fifty() と、適当なリストを filter() に渡してみます。

# PYTHON_FILTER

# In[1]

# 受け取った引数が50以上ならTrue,
# それ以外はFalseを返す関数を定義
def geq_fifty(x):
    if x >= 50:
        return True
    else:
        return False

# リストを作成
numbers = [12, 67, 45, 96, 58, 31, 74, 51]

# numbersから50以上の数値を抽出する
numbers_geq50 = filter(geq_fifty, numbers)

 filter() の戻り値はイテレータとよばれるオブジェクトです。イテレータはリストなどのシーケンスに比べてメモリを節約できますが、必要であれば、list() を使ってイテレータをリストに変換できます。

# In[2]

# イテレータの要素をリストに展開
my_list = list(numbers_geq50)

print(my_list)
[67, 96, 58, 74, 51]

 geq_fifty() を lambda 式で表すと、次のようなコードになります。

# In[3]

# リストの中から50以上の数字を抜き出してイテレータを生成
numbers_geq50 = filter(lambda x : x>=50, numbers)

# イテレータの要素をリストに展開
my_list = list(numbers_geq50)

print(my_list)
[67, 96, 58, 74, 51]

 戻り値が常にリストになるような関数を定義しておくのも一つの手です。

# In[4]

# イテラブルから条件に合う要素を抽出し、
# リストに変換する関数を定義
def filter_list(func, iterable):
    new_iterable = filter(func, iterable)
    return list(new_iterable)

# numbersから50以上の数値を抽出する
my_list = filter_list(lambda x : x>=50, numbers)

print(my_list)
[67, 96, 58, 74, 51]

 今度は filter() を使って特定の文字を含む要素を取り出してみましょう。

# In[5]

# 関数型言語のリスト
functional_languages = ["SML", "Haslkell", "Erlang", "Scheme", "Scala"]

# functional_languagesから"S"を含む要素を抽出
f = filter_list(lambda x : x.find("S") != -1, functional_languages)

print(f)
["SML", "Scheme", "Scala"]

 str.find() は指定した文字列の場所を返すメソッドですが、見つからない場合は -1 を返してきます。x.find("S") != -1 は「"S" が -1 ではない」、すなわち「"S" が文字列のどこかに含まれる」を意味しています。

 filter() の第 1 引数に None を渡すと、第 2 引数のリストをそのままイテレータに変換します。

# In[6]

# 第1引数にNoneを渡すと、イテラブルをイテレータに変換する
numbers_2 = filter(None, numbers)

print(list(numbers_2))
[12, 67, 45, 96, 58, 31, 74, 51]

 これは以下のように、第 1 引数に恒等関数 (lambda x:x) を指定した場合と同じです。

# In[7]

# 第1引数に恒等関数を渡す
numbers_2 = filter(lambda x : x, numbers)

print(list(numbers_2))
[12, 67, 45, 96, 58, 31, 74, 51]

 

【技術英語の豆知識】filter (ろ過する)

 filter を英英辞典で調べてみると、「特別な物質や装置の一部に液体やガスを通してきれいにする」というような説明が英語で書かれています。つまり「ろ過する・濾す」という意味です。名詞だと「ろ過装置」。今は日本語でも普通にフィルターという言葉を使っていますね (コーヒーフィルターとか)。Python の filter() も、条件に合う要素だけを残して、いらない要素は捨ててしまう、いうなれば「ろ過関数」なのです。

itertools.filterfalse()

 標準ライブラリの itertools モジュールには itertools.filterfalse() という関数が用意されています。

filterfalse(function or None, sequence)

 この関数は、function に sequence の各要素を渡したときに False となる要素だけを抽出してイテレータを構築します。以下のサンプルコードでは「偶数を渡すと True, 奇数を渡すと False を返す関数」を function に渡して、リストから奇数を抜き出したイテレータを生成します。

# Python_itertools_filterfalse

import itertools

# arr=[1,2,3,4,5,6,7,8,9]
arr = range(1, 10)

# predicateに「奇数を渡すとFalseを返す関数」を渡すと、
# iterableから奇数となる要素を抽出する
my_iter = itertools.filterfalse(lambda x : x%2==0, arr)

my_list = list(my_iter)

print(my_list)
[1, 3, 5, 7, 9]