我正在尝试编写一个函数来将0和50之间的所有3和5的倍数相加,但是当我告诉它时,Clojure似乎决定不将正确的值添加到我的列表中。
(conj toSum counter)
表单应该将当前数字附加到toSum数组,当循环退出时,(reduce + toSum)
表单应该将数组中的所有内容一起添加。
就目前而言,当调用reduce
函数时,toSum
总是为空,因为conj
函数没有按照它应该做的那样做。我必须搞砸我的逻辑,但我似乎无法弄明白。
(defn calculate [target]
(loop [counter target
toSum []]
(if (= 0 counter)
(reduce + toSum)
(if (or (= 0 (mod counter 3)) (= 0 (mod counter 5)))
(do (conj toSum counter)
(println toSum)
(recur (dec counter) toSum))
(recur (dec counter) toSum)))))
答案 0 :(得分:7)
更实用,更惯用的方法:
(defn multiple-of-3-or-5? [n]
(or (zero? (mod n 3)) (zero? (mod n 5))))
(defn calculate-functional [target]
(->> (range 1 (inc target))
(filter multiple-of-3-or-5?)
(apply +)))
->>
是最后一个宏的线程,此宏接受传递的第一个表单(range
表单)并将其作为下一个表单中的最后一个表单(filter
表单)插入而不是这个新表单,并将其作为apply
表单中的最后一项插入。所以这个宏转换了calculate-functional
函数:
(apply + (filter is-multiple-3-or-5?
(range 1 (inc target))))
在这种情况下,线程最后一个宏不是一个巨大的改进,但是当你使用thread macros的“管道”中有更多步骤时,可以更容易阅读。
(range 1 (inc target))
表单从REPL开始创建seq
,从target
结束:
(range 1 10)
=> (1 2 3 4 5 6 7 8 9)
下一个表达式是(filter multiple-of-3-or-5?)
,filter
保留谓词为true的序列元素。最后(apply +)
使用apply
将+
应用于序列的所有元素。你也可以在这里使用(reduce +)
,我只想展示非常有用的apply
。
答案 1 :(得分:6)
conj
返回一个新集合,它不会改变当前的集合。您需要分配新集合并重复:
(let [nextSum (conj toSum counter)]
(println nextSum)
(recur (dec counter) nextSum))