以下Python代码的Clojure等价物(对于精确算法)是什么?
from itertools import count
from math import sqrt
def prime_gen():
primes = []
for n in count(2):
if all(n%p for p in primes if p <= sqrt(n)):
primes.append(n)
yield n
答案 0 :(得分:10)
这就像我能做到的那样:
(def prime-gen
(let [primes (atom [])]
(for [n (iterate inc 2)
:when (not-any? #(zero? (rem n %))
(filter #(<= % (Math/sqrt n))
@primes))]
(do (swap! primes conj n)
n))))
(take 10 prime-gen) ; => (2 3 5 7 11 13 17 19 23 29)
Clojure不认为整数0是布尔值false。我花了几分钟才发现你的Python代码正在利用这个。
Here是Clojure中的一些其他素数算法。 clojure.contrib.lazy-seqs
中还有一个素数实现。
答案 1 :(得分:0)
这个版本比@Brian Carper的快得多
(def prime-gen
(let [primes (atom [2N])]
(iterate
#(let [ps @primes]
(loop [n (inc %)]
(if (loop [i 0]
(let [p (nth ps i)]
(cond
(< n (* p p)) true
(zero? (mod n p)) false
:else (recur (inc i)))))
(do (swap! primes conj n) n)
(recur (inc n)))))
(first @primes))))
答案 2 :(得分:0)
这是相当惯用的Clojure中的算法。我试图保持名称相同,以便您可以看到这段代码的对应方式。
(def all? (partial every? identity))
(defn prime-gen []
(let [unfold
(iterate
(fn step [[primes n]]
(if (all?
(for [p primes :when (<= p (Math/sqrt n))]
(not= 0 (mod n p))))
[(conj primes n) (inc n)]
(recur [primes (inc n)])))
[[] 2])]
(map (comp peek first) (rest unfold))))
step
的每次迭代
最后一行从迭代中选择附加的素数。
有效:
(take 11 (prime-gen))
=> (2 3 5 7 11 13 17 19 23 29 31)
我们还可以看到一些效率低下的问题:
:when (<= p (Math/sqrt n)
子句(及其等效的Python if p <= sqrt(n)
)是没有用的。我们仍然要遍历所有发现的primes
,而不是在它们变得太大而不能成为可能的因素时停下来。为了弥补这一点,
:when
替换为:while
; primes
包裹在takewhile
中,而不是
紧跟着if
(未试用)。即使如此,该算法也很慢。如需更快的操作,请参见Christophe Grand's blog on the subject中的lazy-primes3
。