添加Vector的元素而不使用`reduce`或`apply`

Yar*_*Yar 0 reduce vector clojure

所以我试图重新实现该reduce方法,因此它可以添加一些通常可以使用的数字reduce,例如:

(reduce + [1 2 3]) ;; 6
(newRd + [1 2 3])  ;; 6
Run Code Online (Sandbox Code Playgroud)

所以我想也许可以使用递归函数来完成,每次调用时都会添加向量的第一个元素,并为向量的其余部分再次执行.像这样的东西:

(defn newRd [list]
  (let [sum 0]
    (if (not= 0 (count list))
      (+ sum (first list))
      (newRd (rest list))
      )
    )
  )
Run Code Online (Sandbox Code Playgroud)

我想我没有正确地进行本地存储.任何建议或更好的方法?

lee*_*ski 10

你的代码中有两个错误:

1)您不会将当前总和添加到递归调用结果中

2)当列表为空时,你应该返回零

更正的变体:

(defn newRd [list]
  (let [sum 0]
    (if (not= 0 (count list))
      (+ sum (first list)
         (newRd (rest list)))
      sum)))
Run Code Online (Sandbox Code Playgroud)

在repl中:

user> (newRd [1 2 3 4])
10
Run Code Online (Sandbox Code Playgroud)

接下来,你可以稍微更新一下:

首先你不需要let声明中的sum ,因为sumalways = 0

第二,有一个lib函数empty?来检查列表是否为空.

(defn newRd [list]
  (if-not (empty? list)
    (+ (first list)
       (newRd (rest list)))
    0))
Run Code Online (Sandbox Code Playgroud)

但请记住:clojure没有尾部调用优化,因此很容易导致堆栈功率流与长列表:

user> (newRd (repeat 1000000 1))
StackOverflowError   user/newRd (form-init289434844644272272.clj:73)
Run Code Online (Sandbox Code Playgroud)

所以最好使用loop/recur

(defn sum-list [list]
  (loop [list list sum 0]
    (if (empty? list)
      sum
      (recur (rest list) (+ sum (first list))))))
Run Code Online (Sandbox Code Playgroud)

在repl中:

user> (sum-list (repeat 1000000 1))
1000000
Run Code Online (Sandbox Code Playgroud)

另一个选择是使函数本身的尾递归:

(defn newRd [list sum]
  (if-not (empty? list)
    (recur (rest list) (+ sum (first list)))
    sum))

user> (newRd (repeat 1000000 1) 0)
1000000
Run Code Online (Sandbox Code Playgroud)

然后你可以添加additoinal arity,以便不在每次调用中传递第二个参数:

(defn newRd
  ([list] (newRd list 0))
  ([list sum]
   (if-not (empty? list)
     (recur (rest list) (+ sum (first list)))
     sum)))
Run Code Online (Sandbox Code Playgroud)