我需要在LISP中创建一个递归方法,该方法获取列表中的数字并查找总和。将跳过列表中不是数字的任何内容(例如,如果列表包含“Cheese 12 Dog 8 Shoe 5”,则输出将为25)。
现在我的代码找到了总和,但如果列表中有任何不是数字的内容,则会抛出错误。有什么可以改变以解决这个问题?
(defun adder (lis)
(cond
((null lis) 0)
(t (eval (cons '+ lis)) )
)
)
答案 0 :(得分:2)
这样做:
(defun adder (lis)
(if (null lis)
0
(let ((c (car lis)))
(if (numberp c)
(+ c (adder (cdr lis)))
(adder (cdr lis))))))
你的版本不是递归的(你没有在加法器中调用加法器),也许你的意思是这样的(非递归的)?
(defun adder (lis)
(apply '+ (remove-if-not 'numberp lis)))
答案 1 :(得分:2)
在可能很长的列表上使用apply
有点危险。如果列表长于call-arguments-limit
,则(apply '+ list)
将无效。现在,call-arguments-limit
在现代Lisps中通常非常大,但允许它小到50。有关此内容的更多信息,请参阅:
(reduce '+ …)
)我认为你最好的选择是使用reduce '+ list
一个关键功能,将每个数字与自身和每个非数字都加到0
。 (这个关键功能是abiessu mentioned in a comment。)
(reduce '+ list :key (lambda (x) (if (numberp x) x 0)))
CL-USER> (let ((list '(cheese 12 dog 8 shoe 5)))
(reduce '+ list :key (lambda (x) (if (numberp x) x 0))))
25
CL-USER> (let ((list '()))
(reduce '+ list :key (lambda (x) (if (numberp x) x 0))))
0
您也可以使用(remove-if-not 'numberp list)
来删除非数字(或(remove-if (complement 'numberp) list)
),而不是使用更复杂的键功能:
CL-USER> (let ((list '(cheese 12 dog 8 shoe 5)))
(reduce '+ (remove-if-not 'numberp list)))
25
CL-USER> (let ((list '()))
(reduce '+ (remove-if-not 'numberp list)))
0