附加到Clojure循环中的数组

附加到Clojure循环中的数组,clojure,Clojure,我正试图编写一个函数,将0和50之间的所有3和5的倍数相加,但Clojure似乎决心在我告诉它时不将正确的值添加到我的列表中 (conj-toSum计数器)表单应该将当前数字附加到toSum数组,当循环退出时(reduce+toSum)表单应该将数组中的所有内容添加到一起 目前,当调用reduce函数时,toSum总是空的,因为conj函数没有完成它应该做的事情。我一定是在什么地方搞砸了我的逻辑,但我似乎弄不明白 (defn calculate [target] (loop [counter

我正试图编写一个函数,将0和50之间的所有3和5的倍数相加,但Clojure似乎决心在我告诉它时不将正确的值添加到我的列表中

(conj-toSum计数器)
表单应该将当前数字附加到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)))))

conj
返回一个新集合,它不会改变当前集合。您需要分配新集合并使用该集合重复出现:

(let [nextSum (conj toSum counter)]
   (println nextSum)
   (recur (dec counter) nextSum))

更实用、更惯用的方法:

(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 +)))
是线程最后一个宏,此宏采用传递的第一个表单(范围
表单)并将其作为下一个表单(过滤器
表单)中的最后一项插入,而不是采用此新表单并将其作为
应用
表单中的最后一项插入。因此,该宏在以下情况下转换
计算函数
函数:

(apply + (filter is-multiple-3-or-5?
                 (range 1 (inc target))))
在这种情况下,thread last宏并不是一个巨大的改进,但是当“管道”中有更多步骤时,使用可以明显更容易阅读

(范围1(inc-target))
表单在REPL处创建一个从1开始到
目标结束的值:

(range 1 10)
=> (1 2 3 4 5 6 7 8 9)

下一个表达式是
(filter multiple-of-3-or-5?
,保留谓词为true的序列元素。最后,
(apply+
用于将
+
应用于序列的所有元素。您也可以在这里使用
(reduce+
,我只是想展示非常有用的
应用程序

toSum
不是数组,它是一个
PersistentVector
conj
只适用于不可变类型,它返回对输入的修改,保持原始输入不变(正如@Lee在回答中指出的),上述方法的另一个好处是,您可以轻松地调整解决方案,以接受用于筛选的谓词作为函数的另一个参数,从而使calculate函数成为一个高阶函数,可用于对由不同谓词筛选的范围求和