在 Clojure 循环中附加到数组
Appending to arrays in a Clojure loop
我正在尝试编写一个函数来将 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)))))
conj
returns 一个新的集合,它不会改变当前的集合。您需要分配新的集合并重复使用:
(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 +)))
->>
是线程最后一个宏,这个宏采用第一个传递的形式(range
形式)并将其作为最后一项插入下一个形式(filter
form) 而不是采用这个新形式并将其作为最后一项插入 apply
形式中。所以这个宏把calculate-functional
函数转换成这样:
(apply + (filter is-multiple-3-or-5?
(range 1 (inc target))))
在这种情况下,thread last macro 并不是一个巨大的改进,但是当您的 "pipeline" 中有更多步骤时,使用 thread macros 可以明显更容易阅读。
(range 1 (inc target))
表单在 REPL 中创建一个从 1 开始到 target
结束的 seq
:
(range 1 10)
=> (1 2 3 4 5 6 7 8 9)
下一个表达式是 (filter multiple-of-3-or-5?)
,filter
keeps the elements of the sequence for which the predicate is true. And finally (apply +)
uses apply
将 +
应用于序列的所有元素。你也可以在这里使用(reduce +)
,我只是想展示非常有用的apply
。
我正在尝试编写一个函数来将 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)))))
conj
returns 一个新的集合,它不会改变当前的集合。您需要分配新的集合并重复使用:
(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 +)))
->>
是线程最后一个宏,这个宏采用第一个传递的形式(range
形式)并将其作为最后一项插入下一个形式(filter
form) 而不是采用这个新形式并将其作为最后一项插入 apply
形式中。所以这个宏把calculate-functional
函数转换成这样:
(apply + (filter is-multiple-3-or-5?
(range 1 (inc target))))
在这种情况下,thread last macro 并不是一个巨大的改进,但是当您的 "pipeline" 中有更多步骤时,使用 thread macros 可以明显更容易阅读。
(range 1 (inc target))
表单在 REPL 中创建一个从 1 开始到 target
结束的 seq
:
(range 1 10)
=> (1 2 3 4 5 6 7 8 9)
下一个表达式是 (filter multiple-of-3-or-5?)
,filter
keeps the elements of the sequence for which the predicate is true. And finally (apply +)
uses apply
将 +
应用于序列的所有元素。你也可以在这里使用(reduce +)
,我只是想展示非常有用的apply
。