我正在学习Clojure,并试图用这种语言解决项目的欧拉(http://projecteuler.net/)问题。第二个问题要求找到斐波那契数列中值不超过四百万的偶值项的总和。
我已经尝试了几种方法,如果我能找到它损坏的地方,我会找到下一个最准确的方法。现在它返回 0。我很确定需要条件有问题,但无法弄清楚。
(reduce +
(take-while (and even? (partial < 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
要以这种方式组合多个谓词,可以使用every-pred
:
(every-pred even? (partial > 4000000))
此表达式的返回值是一个函数,该函数接受参数并在它既等于又大于 4000000 时返回true
,否则false
。
user> ((partial < 4000000) 1)
false
Partial 将静态参数放在首位,将免费参数放在末尾,因此它构建的与您想要的相反。它本质上是产生#(< 4000000 %)
而不是#(< % 4000000)
,所以只需将>
更改为<
:
user> (reduce +
(take-while (and even? (partial > 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464
或者直接使用匿名函数形式会更清楚:
user> (reduce +
(take-while (and even? #(< % 4000000))
(map first (iterate (fn [[a b]] [b (+ a b)]) [0 1]))))
9227464
现在我们已经介绍了一些关于部分的内容,让我们分解一个可行的解决方案。我将使用线程最后一个宏->>
分别显示每个步骤。
user> (->> (iterate (fn [[a b]] [b (+ a b)]) [0 1]) ;; start with the fibs
(map first) ;; keep only the answer
(take-while #(< % 4000000)) ;; stop when they get too big
(filter even?) ;; take only the even? ones
(reduce +)) ;; sum it all together.
4613732
由此我们可以看到,我们实际上并不想在take-while
上将谓词组合evan?
和小于 4000000,因为只要任一条件为真,这就会停止,只留下数字零。相反,我们希望使用其中一个谓词作为限制,另一个谓词作为过滤器。