Игнорировать нечисловые значения в списке и найти рекурсивный метод суммы

Мне нужно создать рекурсивный метод в LISP, который берет числа в списке и находит сумму. Все, что не является числом в списке, пропускается (например, если список содержит "Cheese 12 Dog 8 Shoe 5", результат будет 25).

Прямо сейчас мой код находит сумму, но выдает ошибку, если в списке есть что-то, кроме числа. Что можно изменить, чтобы это исправить?

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

2 ответа

Решение

Это будет делать:

(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)))

С помощью apply в списках, которые могут быть длинными, это немного опасно. Если список длиннее call-arguments-limit, затем (apply '+ list) не сработает Сейчас, call-arguments-limit обычно довольно большой в современных Лиспах, но он может быть не меньше 50. Для получения дополнительной информации об этом см.:

Я думаю, что ваш лучший выбор будет использовать reduce '+ list с ключевой функцией, которая принимает каждое число к себе и каждому не число к 0, (Эта ключевая функция - то, что abiessu упомянул в комментарии.)

(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
Другие вопросы по тегам