附加到Clojure循环中的数组

时间:2015-02-02 22:54:46

标签: clojure

我正在尝试编写一个函数来将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)))))

2 个答案:

答案 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))