web-dev-qa-db-ja.com

pythonで「フィルター」オブジェクトの長さを見つける方法

>>> n = [1,2,3,4]

>>> filter(lambda x:x>3,n)
<filter object at 0x0000000002FDBBA8>

>>> len(filter(lambda x:x>3,n))
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    len(filter(lambda x:x>3,n))
TypeError: object of type 'filter' has no len()

取得したリストの長さを取得できませんでした。だから私はこのように変数に保存しようとしました...

>>> l = filter(lambda x:x>3,n)
>>> len(l)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    len(l)
TypeError: object of type 'filter' has no len()

ループを使用する代わりに、これの長さを取得する方法はありますか?

45
Srichakradhar

何らかの方法でフィルターオブジェクトを反復処理する必要があります。 1つの方法は、リストに変換することです。

_l = list(filter(lambda x: x > 3, n))

len(l)  # <--
_

ただし、リスト内包表記を使用するとより簡単に行うことができるため、そもそもfilter()を使用する意味が失われる可能性があります。

_l = [x for x in n if x > 3]
_

再び、len(l)は長さを返します。

64
arshajii

これは古い質問ですが、この質問にはmap-reduceイデオロギーを使用した回答が必要だと思います。だからここに:

from functools import reduce

def ilen(iterable):
    return reduce(lambda sum, element: sum + 1, iterable, 0)

ilen(filter(lambda x: x > 3, n))

これは、nがコンピューターのメモリに収まらない場合に特に便利です。

22
Al Hoo

docs for python 3は、反復子を返すと言います

「関数がtrueを返すiterableの要素からイテレータを構築します。」

python 2でリストを返しました: here を参照してください。フィルターオブジェクトを反復してその長さを見つける必要があります。

10
doctorlove

フィルタをリストに変換すると、余分なメモリが必要になります。これは、大量のデータには受け入れられない場合があります。リストに変換せずにフィルターオブジェクトの長さを見つけることができます。

sum(1 for _ in filter(lambda x: x > 3, n))

3

一般的に、filterreduceはPythonicではありません。

@arshajiiはこのソリューションを実現しました。

len([x for x in n if x > 3])

これは非常に単純ですが、実行したいことを正確に説明するものではなく、追加のメモリを使用する可能性のあるリストを作成します。より良い解決策は、ジェネレーターでsumを使用することです:

sum(1 for x in n if x > 3)

(ジェネレータの詳細はこちらをご覧ください: https://www.python.org/dev/peps/pep-0289/#rationale

ただし、ジェネレーターを使用したsumは、実装(CPython 3.6.4でテスト済み)のために、実際にはほとんどの場合遅くなります。

In [1]: %timeit len([1 for x in range(10000000)])
356 ms ± 17.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

In [2]: %timeit sum(1 for x in range(10000000))
676 ms ± 7.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3
Ian Lin