Игнорировать нечисловые значения в списке и найти рекурсивный метод суммы
Мне нужно создать рекурсивный метод в 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. Для получения дополнительной информации об этом см.:
- Common lisp: Сколько аргументов может принимать функция? ( этот ответ использует
(reduce '+ …)
) - В Lisp сколько входных данных может иметь функция +?
Я думаю, что ваш лучший выбор будет использовать 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