clojure for function resetts let

max*_*ist 3 variables for-loop clojure let

我试图在4clojure.com上解决一个问题,我应该在不使用的情况下计算集合中的元素数量count.我曾尝试用两种方式forlet我觉得应该工作,但它似乎对环保持复位let.

(#(for [x %  :let [y 0]] (inc y)) [1 2 3 4 5])
;; which returns
(1 1 1 1 1)

(#(let [y 0] (for [x %] (inc y))) [1 2 3 4 5])
;; which returns
(1 1 1 1 1)
Run Code Online (Sandbox Code Playgroud)

所以我的问题是为什么会发生这种情况,以及如何让我的"变量"继续为集合中的每个项目增加值.只是说变量这个词让我想知道我是不是想做一些不可能的东西,但我仍觉得这应该有用.

lee*_*ski 10

在这两种情况下,您都无法改变以下值y:

在第一种情况下for重新介绍y每个循环步骤,这就是为什么你不能改变它的价值,即使它是可变的.

第二种情况表明该值是真正不可变的,为您(inc y)提供每一步,但y始终为零.简单的例子:

(let [x 10]
  (inc x)
  x)

;;=> 10 
Run Code Online (Sandbox Code Playgroud)

通常,这种任务通常可以通过以下方法解决:

第一个是简单的递归:

(defn count-rec [data]
  (if (seq data)
    (inc (count-rec (rest data)))
    0))

user> (count-rec [1 2 3 4 5])
;;=> 5
Run Code Online (Sandbox Code Playgroud)

它在某种程度上是有缺陷的,因为它不是尾递归的,并且对于大型集合会失败

第二个是clojure loop:

(defn count-loop [data]
  (loop [res 0 data data]
    (if (seq data)
      (recur (inc res) (rest data))
      res)))

user> (count-loop [1 2 3 4 5])
;;=> 5
Run Code Online (Sandbox Code Playgroud)

你也可以使用非常相似的显式尾递归:

(defn count-tailrec
  ([data] (count-tailrec 0 data))
  ([c data] (if (seq data)
              (recur (inc c) (rest data))
              c)))

user> (count-tailrec [1 2 3 4 5])
;;=> 5
Run Code Online (Sandbox Code Playgroud)

第三个将使用该reduce功能:

(defn count-reduce [data]
  (reduce (fn [res _] (inc res)) 0 data))

user> (count-reduce [1 2 3 4 5])
;;=> 5
Run Code Online (Sandbox Code Playgroud)

只是为了好玩,你也可以使用这种方式(我不会建议它,因为它与过度杀戮相比reduce):

(defn count-map [data]
  (apply + (map (constantly 1) data)))

user> (count-map [1 2 3 4 5])
;;=> 5
Run Code Online (Sandbox Code Playgroud)

你也可以使用clojure的可变原语,但它不是惯用语,只要它可以是:

(defn count-atom [data]
  (let [c (atom 0)]
    (run! (fn [_] (swap! c inc)) data)
    @c))

user> (count-atom [1 2 3 4 5])
;;=> 5
Run Code Online (Sandbox Code Playgroud)

这是作弊[SPOILER ALERT!]

4clojure count在这个任务中阻止了函数的使用,但是没有阻塞.sizejava集合的方法,所以它可以用 #(.size (seq %))