您要求的是递归函数,尽管在大多数情况下,集合和列表函数比制作自己的递归函数更可取,但这并不总是可行的。这个问题也很容易以惯用的函数方式递归编写,使用 accumulator
这个想法是您从一个空的累加器开始,然后逐步构建您的结果。累加器(此代码 sn-p 中的 acc)将最终保存答案。
(defn add-pairs [v1]
(loop [the-list v1 acc []]
(if (next the-list) ;; checks wether there's more than 1 left in the-list
(recur (rest the-list )
(conj acc (+ (first the-list) (second the-list))))
acc)))
这里发生了什么?你将向量[1 2 3 4] 传递给v1。
然后循环开始并在其中初始化两个变量:
the-list <- [1 2 3 4]
acc []
只需将前两个元素(+ (first the-list) (second the-list) 的总和添加到累加器中即可。然后使用recur 再次调用循环,传递列表的其余部分(rest the-list) 和累加器,现在持有3(作为前两个元素的总和)。新的价值是:
the-list <- [2 3 4]
acc [3]
下一步:
the-list <- [3 4]
acc [3 5]
the-list <- [4]
acc [3 5 7]
然后 if 条件不再成立并返回 else 子句(方便的是累加器,现在持有解决方案)。
总体思路
您从一个空的累加器和您的输入集开始。每一步,累加器都会累积。在大多数情况下,输入集也每一步都在变小。然后满足一些 if 条件并且累加器返回。
在这个特定问题中也非常经典的是输入集在每一步都丢失了它的第一个元素。 (rest ) 在这里非常实用(大多数其他 lisps 中的 cdr )。
一般形式
clojure 中的循环/递归形式非常好,但在许多其他语言中,这种语法缺乏。一个非常经典的解决方案是具有两个函数:一个执行循环的递归函数,一个具有相同名称但另一个执行累加器初始化的 arity。代码比解释简单,所以这里是一些类似 java 的语法:
function add-pairs(v1 acc) {
if (cond)
//do stuff to v1 and acc
add-pairs(v1 acc)
else
return acc }
function add-pairs(v1) {
return add-pairs(v1,[])
}
var result = add-pairs([42 666 1447])