簡體   English   中英

與 `filter(not function, iter)` 相比,使用 `itertools.filterfalse()` 有什么效率優勢嗎?

[英]Are there any efficiency benefits to using `itertools.filterfalse()` as opposed to `filter(not function, iter)`?

標題說明了一切,差不多。 如果我想使用filter function 在range(10)中查找所有大於 5 的數字,我可以這樣做:

result = filter(lambda x: x>5, range(10))

但是, itertools模塊有filterfalse function,據我所知,基本上可以

result = filter(lambda x: not x>5, range(10))

我錯了嗎? 擁有這樣的 function 有什么好處嗎? 與傳統切片相比,其他函數(如islice有一些小的優勢,所以我認為filterfalse也會有一個小眾用途。

我認為 itertools 模塊主要提供便利功能。 它們允許您快速編寫(高效)代碼。 例如,假設您有一些 function 來測試某個屬性,例如測試 object 是否是超過 3 個字符的字符串:

def is_long_string(x):
    return isinstance(x, str) and len(x) > 3

現在,如果您想從對象列表中過濾所有此類字符串,您可以編寫:

input_objects = [1, 2, 3.14, 'foo', 'bar', 'qux', 'xyzzy']
long_strings = list(filter(is_long_string, input_objects))

但是,如果您想擁有所有其他對象,則必須編寫is_not_long_string() function,或使用 lambda ZC1C425268E68385D1AB5074C17A9:F4

not_long_strings = list(filter(lambda x: not is_long_string(x), input_objects))

使用 itertools 您可以更輕松地編寫:

not_long_strings = list(itertools.filterfalse(is_long_string, input_objects))

filterfalse() function 只是提供了內置filter() function 的“反向”操作,即 ZA7F5F35426B927411FC9231B5638271 語言本身缺少的東西。

是否要使用第一種或第二種形式(lambda 或 itertools)是個人喜好問題。

在您的示例中,您已經在使用 lambda function,因此在這種情況下使用 itertools 不會提供更多的可讀性或便利性。

注意:就像 Andrej 在他的回答中已經證明的那樣,性能不是使用 itertools 的主要原因(重寫謂詞 function 可能會帶來更好的性能)。

timeit模塊的快速基准測試表明,使用filter()itertools.filterfalse()具有大致相同的性能。 列表理解肯定更快:

from timeit import timeit
from itertools import filterfalse

N = 10_000

def f1():
    return list(filter(lambda x: x>5, range(N)))

def f2():
    return list(filterfalse(lambda x: not x>5, range(N)))

def f3():
    return [i for i in range(N) if i > 5]


t1 = timeit(lambda: f1(), number=10)
t2 = timeit(lambda: f2(), number=10)
t3 = timeit(lambda: f3(), number=10)

print(t1)
print(t2)
print(t3)

在我的電腦上打印(AMD 2400G、Python 3.8):

0.018814088001818163
0.01380085300115752
0.007684074000280816

編輯: notfilterfalse()中刪除:

from timeit import timeit
from itertools import filterfalse

N = 10_000

def f1():
    return list(filter(lambda x: x>5, range(N)))

def f2():
    return list(filterfalse(lambda x: x<=5, range(N)))

def f3():
    return [i for i in range(N) if i > 5]


t1 = timeit(lambda: f1(), number=10)
t2 = timeit(lambda: f2(), number=10)
t3 = timeit(lambda: f3(), number=10)

print(t1)
print(t2)
print(t3)

印刷:

0.01010196800052654
0.01007204300549347
0.005998152002575807

編輯:使用 Perfplot 進行基准測試:

import perfplot
from itertools import filterfalse


def f1_filter(r):
    return list(filter(lambda x: x>5, r))

def f2_filterfalse(r):
    return list(filterfalse(lambda x: x<=5, r))

def f3_comprehension(r):
    return [i for i in r if i > 5]

def setup(n):
    return range(n)

perfplot.show(
    setup=setup,
    kernels=[f1_filter, f2_filterfalse, f3_comprehension],
    labels=['filter', 'filterfalse', 'comprehension'],
    n_range=[10**i for i in range(1, 7)],
    xlabel='N',
    logx=True,
    logy=True)

顯示:

在此處輸入圖像描述

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM