忽略列表中的非数字值并找到sum递归方法

时间:2013-11-12 18:15:34

标签: list recursion lisp mixed

我需要在LISP中创建一个递归方法,该方法获取列表中的数字并查找总和。将跳过列表中不是数字的任何内容(例如,如果列表包含“Cheese 12 Dog 8 Shoe 5”,则输出将为25)。

现在我的代码找到了总和,但如果列表中有任何不是数字的内容,则会抛出错误。有什么可以改变以解决这个问题?

(defun adder (lis)
   (cond
    ((null lis) 0)
    (t (eval (cons '+ lis)) )
  )
)

2 个答案:

答案 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 '+ 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