【问题标题】:Clojure prime numbers lazy sequenceClojure素数惰性序列
【发布时间】:2010-12-08 02:57:39
【问题描述】:

以下 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

【问题讨论】:

标签: python clojure


【解决方案1】:

这是我能做到的 Python 语言:

(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 是布尔假。我花了几分钟才发现你的 Python 代码正在利用这一点。

Here 是 Clojure 中的其他一些素数算法。 clojure.contrib.lazy-seqs 中还有一个素数实现。

【讨论】:

  • 它不需要是 Pitonish :) 如果对于相同的算法有更惯用的 clojure 解决方案,请也发送。
  • 您应该点击链接。那里有很多例子和答案。还有clj-me.cgrand.net/2009/07/30/….
  • 嗯,除了对atom 进行变异之外,这并不是完全不符合Clojurish 的。不过,要避免使用atom 需要一些扭曲。一些算法需要副作用和非函数式编程风格(尤其是就地排序、洗牌、特定数学函数等),在这些情况下可以切换到使用可变数据结构。这就是 Clojure 提供它们的原因。您甚至可以深入研究并使用原生 Java 数据结构来处理这类事情。
【解决方案2】:

这个版本比@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))))

【讨论】:

    【解决方案3】:

    这是相当惯用的 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 (&lt;= p (Math/sqrt n) 子句(及其 Python 等价物 if p &lt;= sqrt(n))是无用的。我们仍然会检查所有发现的primes,而不是在它们变得太大而成为可能的因素时停止。为了解决这个问题,

    • 在 Clojure 中,我们将 :when 替换为 :while;
    • 在 Python 中,我认为我们将 primes 包装在 takewhile 中,而不是 用if 跟随它(未经测试)。

    即便如此,算法还是很慢。如需更快的内容,请参阅Christophe Grand's blog on the subject 中的lazy-primes3。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-26
      • 2014-06-17
      • 1970-01-01
      • 1970-01-01
      • 2011-07-21
      • 2015-06-12
      • 1970-01-01
      • 2021-05-25
      相关资源
      最近更新 更多