我在玩Python 3的功能性能力,並試圖實現用於計算漢明數字的經典算法。這是隻有2,3或5個主要因素的數字。第一個漢明數字是2,3,4,5,6,8,10,12,15,16,18,20等等。在Python中合併惰性流(使用生成器)
我的實現如下:
def scale(s, m):
return (x*m for x in s)
def merge(s1, s2):
it1, it2 = iter(s1), iter(s2)
x1, x2 = next(it1), next(it2)
if x1 < x2:
x = x1
it = iter(merge(it1, s2))
elif x1 > x2:
x = x2
it = iter(merge(s1, it2))
else:
x = x1
it = iter(merge(it1, it2))
yield x
while True: yield next(it)
def integers():
n = 0
while True:
n += 1
yield n
m2 = scale(integers(), 2)
m3 = scale(integers(), 3)
m5 = scale(integers(), 5)
m23 = merge(m2, m3)
hamming_numbers = merge(m23, m5)
它是合併似乎是行不通的問題。在此之前,我實現埃拉托色尼的篩以同樣的方式,和它的工作完全沒問題:
def sieve(s):
it = iter(s)
x = next(it)
yield x
it = iter(sieve(filter(lambda y: x % y, it)))
while True: yield next(it)
這一個使用相同的技術,我的合併操作。所以我看不出有什麼區別。你有什麼想法? (我知道所有這些都可以通過其他方式實現,但我的目標正是爲了理解Python的生成器和純功能性能,包括遞歸,而不使用類聲明或特殊的預構建Python函數。)
UPD:威爾內斯這裏是我實現這個算法在LISP(球拍實際上):
(define (scale str m)
(stream-map (lambda (x) (* x m)) str))
(define (integers-from n)
(stream-cons n
(integers-from (+ n 1))))
(define (merge s1 s2)
(let ((x1 (stream-first s1))
(x2 (stream-first s2)))
(cond ((< x1 x2)
(stream-cons x1 (merge (stream-rest s1) s2)))
((> x1 x2)
(stream-cons x2 (merge s1 (stream-rest s2))))
(else
(stream-cons x1 (merge (stream-rest s1) (stream-rest s2)))))))
(define integers (integers-from 1))
(define hamming-numbers
(stream-cons 1 (merge (scale hamming-numbers 2)
(merge (scale hamming-numbers 3)
(scale hamming-numbers 5)))))
感謝您的代碼。是的,這就像經典的哈斯克爾一樣 - 例如這裏rosettacode.org/wiki/Hamming_numbers(也有一些其他非常有趣的代碼,也是基於流的Scheme代碼,位於http://c2.com/cgi/wiki?SieveOfEratosthenesInManyProgrammingLanguages)。我想這一切都始於SICP mitpress.mit.edu/sicp/full-text/sicp/book/node71.html。 :) –