這不會有任何顯式循環或致電max
功能。該函數假定輸入列表中至少有五個元素,並輸出一個元組(start_index, max_product)
。
from functools import reduce, partial
import operator
def f(l):
win = zip(l, l[1:], l[2:], l[3:], l[4:])
products = map(partial(reduce, operator.mul), win)
return reduce(lambda x, y: x if x[1] > y[1] else y, enumerate(products))
In [2]: f([1, 2, 3, 4, 7, 8, 9])
Out[2]: (2, 6048)
In [3]: f([2, 6, 7, 9, 1, 4, 3, 5, 6, 1, 2, 4])
Out[3]: (1, 1512)
win = zip(l, l[1:], l[2:], l[3:], l[4:])
創建在輸入列表大小5的滑動窗口迭代器。 products = map(partial(reduce, operator.mul), win)
是在win
的每個元素上調用partial(reduce, operator.mul)
(轉換爲reduce(operator.mul, ...)
)的迭代器。 reduce(lambda x, y: x if x[1] > y[1] else y, enumerate(products))
將計數器添加到products
並返回具有最高值的索引 - 值對。
如果你需要一個更一般的版本和/或輸入列表很大,你會使用itertools.islice
:
from itertools import islice
def f(l, n=5):
win = zip(*(islice(l, i, None) for i in range(n)))
...
上面的代碼使用生成器表達式這是一個循環,在技術上。這方面的一個純功能的版本可能看起來像
from itertools import islice
def f(l, n=5):
win = zip(*map(lambda i: islice(l, i, None), range(n)))
...
'map'和'reduce'使用'loops'幕後,試圖避免'列表comprehensions'例如使用循環將要相當困難,並沒有真正的好處。 –
如果您使用遞歸,您幾乎可以直接避免循環。 Haskell這樣做。但是,Haskell對此進行了優化,Python可能不會。所以你會很快進入最大遞歸深度。 - 無論如何,你在動作風格上做什麼動機? –
函數式編程=/=避免循環。 – trincot