filter實(shí)現(xiàn)素?cái)?shù)算法

素?cái)?shù)算法

看到廖雪峰網(wǎng)站上用python的實(shí)現(xiàn), 看起來(lái)很簡(jiǎn)單, 但是最終還是自己實(shí)現(xiàn)一遍比較好, ==代碼點(diǎn)我跳轉(zhuǎn).==

原理很簡(jiǎn)單, 在數(shù)學(xué)界1既不是質(zhì)數(shù)也不是合數(shù), 所以不用管1, 從2開(kāi)始

輸出最小的質(zhì)數(shù)`2`, 然后將`2`的倍數(shù)都刪除
輸出剩下的第一個(gè)數(shù)為`3`, 然后將`3`的倍數(shù)都刪除
輸出剩下的第一個(gè)數(shù)為`5`, 然后將`5`的倍數(shù)都刪除
輸出剩下的第一個(gè)數(shù)為`7`, 然后將`7`的倍數(shù)都刪除
...

這樣不斷循環(huán)下去, 直到所有的數(shù)都被刪除或者輸出, 輸出的數(shù)即為質(zhì)數(shù).

  • 實(shí)現(xiàn)
def _ori_iter():
    n = 1
    while True:
        n += 2
        yield n

這里先定義一個(gè)ori_iter方法, 返回的是一個(gè)生成器(從3開(kāi)始的奇數(shù), 如 3, 5, 7...)

def _not_divisible(n):
    return lambda x: x % n > 0

這里定義了一個(gè)_not_divisible方法, 這可以理解成一種規(guī)則, x能整除n返回false, 不能整除則返回true, 后面filter中有用到

def prime():
    it = _ori_iter()
    while True:
        n = next(it)
        yield n
        # it = filter(lambda x: x % n > 0, it)
        it = filter(_not_divisible(n), it)

這里定義的prime返回的則是全體素?cái)?shù). 第一行的it = _ori_iter(), 這時(shí)it是一個(gè)會(huì)返回從3開(kāi)始的所有奇數(shù)(也就是不能被2整除)的生成器==(3, 5, 7, 9, 11...)==, while True表示將會(huì)無(wú)限循環(huán)下去,直到天荒地老, 下面是循環(huán)過(guò)程

  1. 取出的第一個(gè)nit的第一個(gè)元素3, yield n3作為prime生成器的第一個(gè)元素. 之后經(jīng)過(guò)it = filter(_not_divisible(n), it), 這里的it經(jīng)過(guò)篩選, 將3的倍數(shù)全部丟棄==(3, 5, 7, 9, 11...)==
  2. 取出被篩選過(guò)的it的第二個(gè)元素, 也就是5, 作為prime生成器的第二個(gè)元素. 之后在經(jīng)過(guò)it = filter(_not_divisible(n), it)篩選, 將5的倍數(shù)全部丟棄(3, 5, 7, 11, 13, 15...)
  3. 取出被篩選過(guò)的it的第三個(gè)元素, 也就是7, 作為prime生成器的第三個(gè)元素. 之后在經(jīng)過(guò)it = filter(_not_divisible(n), it)篩選, 將7的倍數(shù)全部丟棄(3, 5, 7, 11, 13...21...)
  4. ...

這是一個(gè)無(wú)限循環(huán), 所以prime返回的是一個(gè)的生成器, 里面包含無(wú)窮多個(gè)質(zhì)數(shù)

  • 總結(jié)
    算法很容易理解, 實(shí)現(xiàn)起來(lái)也并不難, 下面是在實(shí)現(xiàn)的過(guò)程中遇到的一個(gè)問(wèn)題
def _not_divisible(n):
    return lambda x: x % n > 0

def prime():
    it = _ori_iter()
    while True:
        n = next(it)
        yield n
        # it = filter(lambda x: x % n > 0, it)
        it = filter(_not_divisible(n), it)

最后兩句分為注釋部分it = filter(lambda x: x % n > 0, it)和未注釋部分it = filter(_not_divisible(n), it)咋一看并沒(méi)有什么區(qū)別, 但是輸出的結(jié)果卻大有不同, 這就有意思了, 思前想后, 請(qǐng)教同事, 最后總算是有點(diǎn)理解, 這里大致描述一下為什么會(huì)出現(xiàn)輸出不同的情況...

生成器(Iterator)是一種惰性計(jì)算的序列(他很懶, 你催他一下, 他才會(huì)給你下一個(gè)數(shù)據(jù)- -), 只有當(dāng)你使用next取值時(shí), 才會(huì)去執(zhí)行, 然后返回給你正確的值

  • 這里如果使用未注釋部分, it = filter(lambda x: x % n > 0, it)這里的n值確實(shí)是上一句正確返回的n值, 但是由于filter也是惰性的, filter只會(huì)去執(zhí)行一次篩選, 然后到下次循環(huán)時(shí), n的值就變了成下次返回的n, 這樣每次filter都只會(huì)篩選一次, 真正需要篩選出去的值并沒(méi)有被篩選, 最后的執(zhí)行結(jié)果顯然不會(huì)正確了...
  • 然而使用未注釋部分代碼, n的值是通過(guò)_not_divisible函數(shù)的參數(shù)傳進(jìn)去的, 不會(huì)去改變, 傳進(jìn)去第一個(gè)3, 他就會(huì)一直篩選下去, 然后傳進(jìn)第二個(gè)5的時(shí)候, 同理也會(huì)篩選下去, 所以可以得出正確的質(zhì)數(shù)序列

歸根結(jié)底, 這里應(yīng)該是filterlambda內(nèi)部處理的問(wèn)題, 可能研究一下源碼會(huì)更加明了, 這里就先不倒騰了/哭笑...

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容