[解決!Python]filter関数でリストや辞書から要素を抽出するには:解決!Python
filter関数を使って反復可能オブジェクトの要素の中で特定の条件に合致するものだけを抽出する方法を紹介する。
def is_even(x):
return x % 2 == 0
result = filter(is_even, [1, 2, 3, 4]) # リスト(反復可能オブジェクト)から偶数を抽出
# filter関数の戻り値はイテレータ(filterオブジェクト)
print(result) # <filter object at 0xXYZ...>
for item in result: # forループで処理する
print(item)
# 出力結果:
#2
#4
# list関数でリストに変換する
result = filter(is_even, [1, 2, 3, 4])
result = list(result)
print(result) # [2, 4]
# 同じことをするリスト内包表記
result = [num for num in [1, 2, 3, 4] if is_even(num)]
print(result) # [2, 4]
# ラムダ式を使う例
result = filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
print(list(result)) # [2, 4]
# 関数を指定しない場合
result = filter(None, [0, 1, '', 'foo', True, False, None])
print(list(result)) # [1, 'foo', True]
# result = [item for item in [0, 1, '', 'foo', True, False, None] if item]
# 辞書の要素
data = {'foo': '000', 'bar': 'AAA', 'baz': '+++'}
result = filter(lambda k: k.startswith('ba'), data.keys()) # キーを反復
print(list(result)) # ['bar', 'baz']
# result = [k for k in data if k.startswith('ba')]
result = filter(lambda v: v.isalnum(), data.values())
print(list(result)) # ['000', 'AAA']
# result = [v for v in data.values() if v.isalnum()]
result = filter(lambda item: item[1].isalpha(), data.items())
print(dict(result)) # {'bar': 'AAA'}
# result = {item[0]: item[1] for item in data.items() if item[1].isalpha()}
# 辞書の辞書
data = {
'kawasaki': {'height': 129, 'weight': 129, 'age': 129},
'isshiki': {'height': 168, 'weight': 66, 'age': 26},
'endo': {'height': 175, 'weight': 80, 'age': 48}
}
result = filter(lambda item: item[0] == 'kawasaki', data.items())
print(dict(result)) # {'kawasaki': {'height': 129, 'weight': 129, 'age': 129}}
# result = {item[0]: item[1] for item in data.items() if item[0] == 'kawasaki'}
result = filter(lambda item: item[1]['height'] > 170, data.items())
print(dict(result)) # {'endo': {'height': 175, 'weight': 80, 'age': 48}}
# result = {item[0]: item[1] for item in data.items() if item[1]['height'] > 170}
filter関数の基本
Pythonのfilter関数は第1引数に指定した関数(ラムダ式、呼び出し可能オブジェクトなど)を用いて第2引数に指定した反復可能オブジェクトの要素を評価して、その結果が真となる要素だけを反復するイテレータを返送する。
filter(function, iterable)
map関数では反復可能オブジェクトを複数指定可能だが、filter関数では受け取る反復可能オブジェクトは1つだけである。また、functionに指定する関数の引数は1つだけである必要がある。
簡単な例を以下に示す。
def is_even(x):
return x % 2 == 0
result = filter(is_even, [1, 2, 3, 4]) # リスト(反復可能オブジェクト)から偶数を抽出
# filter関数の戻り値はイテレータ(filterオブジェクト)
print(result) # <filter object at 0xXYZ...>
この例では引数を1つ受け取り、それが偶数であればTrueを、そうでなければFalseを返すis_even関数を定義して、整数リストの要素から偶数だけを抽出している。戻り値はmap関数と同様にイテレータとなる点には注意しよう。
そのため、抽出した要素を扱うには、以下のようにループで各要素を順次取り扱うか、list関数でリストに変換するなどの処理を行う。
for item in result: # forループで処理する
print(item)
# 出力結果:
#2
#4
# list関数でリストに変換する
result = filter(is_even, [1, 2, 3, 4])
result = list(result)
print(result) # [2, 4]
なお、Pythonではfilter関数を使った要素の抽出と同じことを、リスト内包表記などを用いても実現できる。例えば、以下は上と同じことをリストの内包表記を用いて行う例だ。
result = [num for num in [1, 2, 3, 4] if is_even(num)]
print(result) # [2, 4]
リスト内包表記では最後にif句を置き、そこに抽出の条件を記述する。
最初の例では、自作の関数を定義していたが、ラムダ式を使ってfilter関数に抽出の条件を直接記述することも可能だ。以下に例を示す。
result = filter(lambda x: x % 2 == 0, [1, 2, 3, 4])
print(list(result)) # [2, 4]
なお、第1引数にNoneを指定した場合には、恒等関数を指定したものと見なされる。これはラムダ式を使って表現すると、「lambda x: x」である。つまり、受け取ったものをそのまま返す。よって、filter関数に渡した反復可能オブジェクトの要素のうち、真となるものだけが抽出される。
result = filter(None, [0, 1, '', 'foo', True, False, None])
print(list(result)) # [1, 'foo', True]
# result = [item for item in [0, 1, '', 'foo', True, False, None] if item]
この例では、反復可能オブジェクトとして[0, 1, '', 'foo', True, False, None]を指定しているが、その要素の中で0や空文字列、False、Noneは偽と見なされる。よって、filter関数が返送するイテレータはそれ以外の真と見なされる要素である1、'foo'、Trueを反復する。コメントとして記述したが、リスト内包表記では「if item」句を最後に付加したことと同義になる。
リスト以外にも反復可能オブジェクトであれば、何でもfilter関数に渡せる。
Copyright© Digital Advantage Corp. All Rights Reserved.