filter高階函式和Iterator惰性計算的配合
在網路上看到一種python計算素數的方法,覺得對理解filter和Iterator很有幫助,僅在此記錄下來。
一,不同於一般的素數計算方案:
計算素數的一個方法是埃氏篩法,它的演算法理解起來非常簡單:
首先,列出從2
開始的所有自然數,構造一個序列:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取序列的第一個數2
,它一定是素數,然後用2
把序列的2
的倍數篩掉:
3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取新序列的第一個數3
,它一定是素數,然後用3
把序列的3
的倍數篩掉:
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
取新序列的第一個數5
,然後用5
把序列的5
的倍數篩掉:
7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...
不斷篩下去,就可以得到所有的素數。
二,python實現
如果換成c或java語言,那麼勢必要把序列的範圍控制住,因為它們不能表示自然數這樣的無窮序列。
然而python的Iterator的惰性計算就支援表示這樣的無窮序列。
關於生成器和Iterator的內容詳見https://blog.csdn.net/qq_21294095/article/details/85082299和https://blog.csdn.net/qq_21294095/article/details/85080891
用生成器表示自然數:
def g1(): #從2開始的自然數無窮序列
n = 1
while True:
n = n + 1
yield n
建立過濾函式:
def _not_divisible(n): #篩選函式 x除不盡n 返回True return lambda x: x%n > 0 #篩選函式只能接收一個引數,所以這裡用閉包來儲存除數n #因為返回了一個匿名函式 並且引數x由 filter的第二個引數一一提供
建立一個素數生成器:
def prims():
nn = g1()
while True:
n = next(nn) #自然數生成器開始計算第一個自然數
yield n
nn = filter(_not_divisible(n), nn) #用剛剛得到的n對 nn進行過濾, 建立一個新的生成器
輸出這個素數生成器:
for i in prims():
if i < 50:
print(i, end=' ')
else:
break
Output:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47
需要著重理解的式,prims()這個素數生成器是如何工作的,其實兩句註釋已經寫的很詳細了。
參考:
對文中程式碼進行了修改和必要的註釋