在不使用 `reduce` 或 `apply` 的情况下添加 Vector 的元素
Adding the elements of a Vector without using `reduce` or `apply`
所以我正在尝试重新实现 reduce
方法,因此它可以添加一些通常可以使用 reduce
完成的数字,例如:
(reduce + [1 2 3]) ;; 6
(newRd + [1 2 3]) ;; 6
所以我想也许可以使用递归函数来完成,该函数在每次调用时添加向量的第一个元素,然后对向量的其余部分再次执行此操作。像这样:
(defn newRd [list]
(let [sum 0]
(if (not= 0 (count list))
(+ sum (first list))
(newRd (rest list))
)
)
)
我想我没有正确地进行本地存储。有什么建议或更好的方法吗?
您的代码中有两个错误:
1) 你没有把你当前的总和加到递归调用结果中
2) 当列表为空时你应该return零
更正变体:
(defn newRd [list]
(let [sum 0]
(if (not= 0 (count list))
(+ sum (first list)
(newRd (rest list)))
sum)))
回复:
user> (newRd [1 2 3 4])
10
接下来,大家可以稍微更新一下:
首先你并不需要 let
语句中的总和,因为 sum
总是 = 0
其次,有一个库函数empty?
来检查列表是否为空。
(defn newRd [list]
(if-not (empty? list)
(+ (first list)
(newRd (rest list)))
0))
但是记住:clojure不做尾调用优化,所以长列表很容易造成stack owerflow:
user> (newRd (repeat 1000000 1))
WhosebugError user/newRd (form-init289434844644272272.clj:73)
所以最好使用loop/recur
(defn sum-list [list]
(loop [list list sum 0]
(if (empty? list)
sum
(recur (rest list) (+ sum (first list))))))
回复:
user> (sum-list (repeat 1000000 1))
1000000
另一种选择是使函数本身尾递归:
(defn newRd [list sum]
(if-not (empty? list)
(recur (rest list) (+ sum (first list)))
sum))
user> (newRd (repeat 1000000 1) 0)
1000000
然后你可以添加额外的参数,不要在每次调用时传递第二个参数:
(defn newRd
([list] (newRd list 0))
([list sum]
(if-not (empty? list)
(recur (rest list) (+ sum (first list)))
sum)))
进一步 ...
一般来说,您不妨实施 new-reduce
(驼峰式大小写不是惯用的):
(defn new-reduce
([f init coll]
(if (seq coll)
(recur f (f init (f init (first coll))) (rest coll))
init))
([f coll]
(if (seq coll)
(reduce f (first coll) (rest coll))
(f))))
然后
(new-reduce + [1 2 3]) ;; 6
这或多或少是 reduce
的源代码直到最近的样子,如果你去掉分块的话。
您使用的双参数版本依赖于三参数版本,您可以直接 recur
,无需显式 loop
。这需要每次都传递 f
,但这就是它过去所做的。大概携带一个额外的参数比在本地范围内工作更快。
所以我正在尝试重新实现 reduce
方法,因此它可以添加一些通常可以使用 reduce
完成的数字,例如:
(reduce + [1 2 3]) ;; 6
(newRd + [1 2 3]) ;; 6
所以我想也许可以使用递归函数来完成,该函数在每次调用时添加向量的第一个元素,然后对向量的其余部分再次执行此操作。像这样:
(defn newRd [list]
(let [sum 0]
(if (not= 0 (count list))
(+ sum (first list))
(newRd (rest list))
)
)
)
我想我没有正确地进行本地存储。有什么建议或更好的方法吗?
您的代码中有两个错误:
1) 你没有把你当前的总和加到递归调用结果中
2) 当列表为空时你应该return零
更正变体:
(defn newRd [list]
(let [sum 0]
(if (not= 0 (count list))
(+ sum (first list)
(newRd (rest list)))
sum)))
回复:
user> (newRd [1 2 3 4])
10
接下来,大家可以稍微更新一下:
首先你并不需要 let
语句中的总和,因为 sum
总是 = 0
其次,有一个库函数empty?
来检查列表是否为空。
(defn newRd [list]
(if-not (empty? list)
(+ (first list)
(newRd (rest list)))
0))
但是记住:clojure不做尾调用优化,所以长列表很容易造成stack owerflow:
user> (newRd (repeat 1000000 1))
WhosebugError user/newRd (form-init289434844644272272.clj:73)
所以最好使用loop/recur
(defn sum-list [list]
(loop [list list sum 0]
(if (empty? list)
sum
(recur (rest list) (+ sum (first list))))))
回复:
user> (sum-list (repeat 1000000 1))
1000000
另一种选择是使函数本身尾递归:
(defn newRd [list sum]
(if-not (empty? list)
(recur (rest list) (+ sum (first list)))
sum))
user> (newRd (repeat 1000000 1) 0)
1000000
然后你可以添加额外的参数,不要在每次调用时传递第二个参数:
(defn newRd
([list] (newRd list 0))
([list sum]
(if-not (empty? list)
(recur (rest list) (+ sum (first list)))
sum)))
进一步
一般来说,您不妨实施 new-reduce
(驼峰式大小写不是惯用的):
(defn new-reduce
([f init coll]
(if (seq coll)
(recur f (f init (f init (first coll))) (rest coll))
init))
([f coll]
(if (seq coll)
(reduce f (first coll) (rest coll))
(f))))
然后
(new-reduce + [1 2 3]) ;; 6
这或多或少是 reduce
的源代码直到最近的样子,如果你去掉分块的话。
您使用的双参数版本依赖于三参数版本,您可以直接 recur
,无需显式 loop
。这需要每次都传递 f
,但这就是它过去所做的。大概携带一个额外的参数比在本地范围内工作更快。