[英]Speeding up summation in Python
我在listn1
有一個包含數字n1
的大列表。 我想添加每個數字的所有倍數,如果被乘數不在另一個列表listn2
(具有特定特征的素數)並且乘積低於最大值max_n
。 在大多數情況下,被乘數小於 10,但可以達到 100,000。 到目前為止,我的代碼如下所示:
s = 0
for n1 in listn1:
s += sum(n1 * i for i in range(1, 1 + max_n // n1) if i not in listn2)
問題:這種方法太慢了。 計算listn1
和listn2
需要幾秒鍾,所以我知道有超過一百萬個數字要添加。 但是我昨天晚上開始求和,今天早上它仍在運行。
有沒有一種 Pythonic 的方法來加速這個求和?
我有2個建議給你。
首先,您沒有在每次迭代時將i
與n1
相乘。 你可以更換
s += sum(n1 * i for i in range(1, 1 + max_n // n1) if i not in listn2)
與
s += n1 * sum(i for i in range(1, 1 + max_n // n1) if i not in listn2)
他們完全一樣。
其次, if i not in listn2
條件下,你有一個簡單的總結:
sum(i for i in range(1, 1 + max_n // n1)
這與sum([1, 2, 3, 4, 5, 6, 7, 8, ..., (max_n // n1)])
,並且等於(max_n // n1) * (1 + max_n // n1) / 2
。 舉個簡單的例子,看看這個。
要處理if i not in listn2
條件下,如果您的listn2
較小,您可以總結listn2
而不是listn1
。
因此,找到的總和listn1
核減的項目listn2
:
def sum_until(l, max):
return sum([x for x in l if x < max])
listn2 = list(set(listn2))
for n1 in listn1:
finish = max_n // n1
s += n1 * (finish * (finish + 1) / 2 - sum_until(listn2, finish))
編輯:
我想 NumPy 的總和會更快。 使listn2
成為一個 numpy 數組:
import numpy as np
listn2 = np.array(list(set(listn2)))
並使用這個sum_until
函數:
def sum_until(listn2, max):
l = listn2[np.where(listn2 <= max)]
return int(np.sum(l))
根據船上的建議,我將代碼重新編寫為
setn2 = set(listn2)
s = 0
for n1 in listn1:
s += n1 * (max_n * (max_n + 1) // 2 - sum(i for i in range(1, 1 + max_n // n1) if i in setn2))
求和現在只需要幾秒鍾,而不是幾小時。
幾個小時后
遇到我的這個老問題,回想起來,我做了正確的事情。 這個想法在這個線程提到這里使用numpy.sum()
而不是良好意圖,但錯了,如圖所示這里。 如果您使用 numpy,那很好,但是如果您有 Python 列表,請使用推導式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.