聲明我有一個下列用例:捕獲方法,如果在列表理解
[(x, f(x)) for x in list_x if f(x) == cond(x)]
上面所列內容的理解,我覺得使得F(X)調用兩次?我該如何避免並捕獲f(x)的值,以便f(x)只被調用一次。
我想,簡單的解決辦法是將上面的列表理解轉換爲for循環,但我好奇,如果它可以使用列表理解有效地完成。
聲明我有一個下列用例:捕獲方法,如果在列表理解
[(x, f(x)) for x in list_x if f(x) == cond(x)]
上面所列內容的理解,我覺得使得F(X)調用兩次?我該如何避免並捕獲f(x)的值,以便f(x)只被調用一次。
我想,簡單的解決辦法是將上面的列表理解轉換爲for循環,但我好奇,如果它可以使用列表理解有效地完成。
您可以使用嵌套生成器表達式來調用該函數只有一次:
[(x, fx) for (x, fx) in ((x, f(x)) for x in list_x) if fx == cond(x)]
生成器表達式以鎖步形式迭代以生成列表理解的元組(x, fx)
。
如果您發現讀者容易些,你可以打出發電機表達到一個單獨的名頭:
mapped_x = ((x, f(x)) for x in list_x)
filtered_x = [(x, fx) for (x, fx) in mapped_x if fx == cond(x)]
再次重申了這一點:發電機表達式執行懶洋洋的;表達式中的for
循環對於for ... in mapped_x
循環中的每個步驟都是逐步進階的。
演示:
>>> list_x = range(5)
>>> f = lambda x: print('f({!r})'.format(x)) or (x ** 2 - 1)
>>> cond = lambda x: print('cond({!r})'.format(x)) or x % 2 == 0
>>> mapped_x = ((x, f(x)) for x in list_x)
>>> [(x, fx) for (x, fx) in mapped_x if fx == cond(x)]
f(0)
cond(0)
f(1)
cond(1)
f(2)
cond(2)
f(3)
cond(3)
f(4)
cond(4)
[(1, 0)]
注f(x)
是如何調用只有一次,條件是立即檢查。
這是多高效取決於呼叫的代價是多少;生成器表達式作爲單獨的功能框架執行,並且解釋器將在兩個框架之間切換(用於列表理解的循環也是框架對象)。
如果f(x)
是一個Python函數,你已經贏了,因爲你現在減半創建的功能框對象的數量(每個f(x)
調用創建一個框架對象太多,而創建這些成本相對較高)。對於C函數,您應該使用timeit
module創建一些試運行,以查看預期列表大小的更快速度。
如果你不想叫f
兩次,則可以申請f
到列表第一
[a for a in map(lambda x: (x, f(x)), list_x) if a[1] == cond(x)]
過濾器將是一個乾淨的方式來做到這一點。它會評估傳遞的函數,如果它返回true,它將保留該元素,否則,不。
print (list(filter(lambda x: x[1] == cond(x[0]), [(x, f(x)) for x in list_x])))
如果你使用'map'爲什麼不使用'filter'呢?... – Julien
歡迎您提供您的答案 –
注意版本,使用'lambda'顯著減慢下來(創建和彈出對於列表長度N,功能框架對象N次)。 –