我正在尝试解决项目欧拉问题,要求您提供第n个素数,例如第6个素数是13。
我的代码如下所示:
(ns scratch.core
(require [clojure.string :as str :only (split-lines join)]))
(def t "2\n3\n6")
(defn work [input]
(let [lines (map read-string (str/split-lines input))]
(letfn [(is-prime? [n]
(or
(= n 2)
(empty? (filter #(= 0 (mod n %)) (range 2 (inc (Math/sqrt n)))))))
(parse-primes [[x & xs]]
(prn (last (take x (filter #(is-prime? %) (iterate inc 2)))))
(if (seq xs)
(recur xs)))]
(parse-primes (rest lines)))))
(work t)
(def t 2\n3\n6)
只是我的测试数据,虽然最大值是10 ^ 4,但我不知道验证答案的程序的实际数字是多少。
我对这段代码感到惊讶,有人可以提出潜在的瓶颈吗?
答案 0 :(得分:0)
首先,您有理由在最后执行(parse-primes (rest lines))
而不是(parse-primes lines)
吗?当您的输入String
仅包含1个值时会产生异常,例如"6"
。
然后,正如@ntalbs建议你应该在每个职能中分离一些关注点。保持算法的思路,你可以让parse-primes
生成无限的素数序列而不是打印并在输入上重复出现:
(parse-primes []
(filter #(is-prime? %) (iterate inc 2)))
然后添加一个特定的函数来获得Nth prime:
(nth-prime [n]
(nth (parse-primes) n))
然后,您可以将work
函数(parse-primes lines)
的主要部分替换为(map nth-prime lines)
,这会使此函数返回序列而不是作为副作用打印并返回nil
。
作为清理问题,您可以删除work
的输入解析以匹配现在返回的序列:
(defn work [rank-of-primes]
(letfn [...]
(map nth-prime rank-of-primes)))
(let [ranks-of-primes (map read-string (str/split-lines input))]
(work ranks-of-primes))
现在只是为了提高性能,您只能测试2
中的奇数和is-prime?
数字,并使用not-any?
进行简化。
(is-prime? [n]
(not-any? #(= 0 (mod n %))
(cons 2 (range 3 (inc (Math/sqrt n)) 2)))
此时,如果不修改你选择的算法,它应该更清洁一点:
(defn work [rank-of-primes]
(letfn [(is-prime? [n]
(not-any? #(= 0 (mod n %))
(cons 2 (range 3 (inc (Math/sqrt n)) 2))))
(parse-primes []
(cons 2 (filter #(is-prime? %)
(cons 2 (iterate (partial + 2) 3)))))
(nth-prime [n]
(nth (parse-primes) n))]
(map nth-prime rank-of-primes)))
(let [input "2\n3\n6\n10000"
ranks-of-primes (map read-string (str/split-lines input))]
(work ranks-of-primes))
在素数问题上有很多值得探讨的问题。如果您对Clojure中的素数算法感兴趣,那么来自C.Grand的blog post更多参与其中。