1. 程式人生 > >filter高階函式和Iterator惰性計算的配合

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/85082299https://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()這個素數生成器是如何工作的,其實兩句註釋已經寫的很詳細了。

 

參考:

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431821084171d2e0f22e7cc24305ae03aa0214d0ef29000

對文中程式碼進行了修改和必要的註釋