【问题标题】:Ignore non-number values in a list and find the sum recursive method忽略列表中的非数字值并找到求和递归方法
【发布时间】:2013-11-12 18:15:34
【问题描述】:

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

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

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

【问题讨论】:

  • numberp 确定项目是否为数字...类似于...(cons '+ (map 'list #'(lambda (x) (if (numberp x) x 0)) lis))...

标签: list recursion lisp mixed


【解决方案1】:

这样可以:

(defun adder (lis)
  (if (null lis)
    0
    (let ((c (car lis)))
      (if (numberp c)
        (+ c (adder (cdr lis)))
        (adder (cdr lis))))))

您的版本不是递归的(您没有在 adder 内部调用 adder),也许您的意思是这样的(非递归的)?

(defun adder (lis)
  (apply '+ (remove-if-not 'numberp lis)))

【讨论】:

    【解决方案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
    

    【讨论】:

    • 我忘记了写reduceremove-*操作的简单方法,谢谢提醒。 :-)
    • @abiessu 好吧,我确实认为这种方式更简单,但更重要的是,它更安全,因为如果您的列表比call-arguments-limit 长,那么(apply '+ list) 赢了不行,因为(reduce '+ list) 仍然可以。
    猜你喜欢
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多