Изменение списка не имеет особого смысла, потому что оно становится волосатым во главе списка, чтобы сохранить исходную ссылку. Вернуть новый список.
Это операция фильтрации. Обычный оператор в Common Lisp для этого - remove-if-not
(или remove-if
, или remove
, в зависимости от условия). Требуется предикат, который должен возвращать, должен ли элемент быть сохранен. В этом случае, кажется, (lambda (element) (and (listp element) (>= (length element) minlength)))
.
(defun filter-by-min-length (minlength list)
(remove-if-not (lambda (element)
(and (listp element)
(>= (length element) minlength)))
list))
Во многих случаях, когда условие известно во время компиляции, loop
производит более быстрый скомпилированный код:
(defun filter-by-min-length (minlength list)
(loop :for element :in list
:when (and (listp element)
(>= (length element) minlength))
:collect element))
Возвращает новый список, который удовлетворяет условию. Вы бы назвали это как (let ((minlength-list (filter-by-min-length 2 raw-list))) …)
.
Многие базовые курсы вначале настаивают на рекурсивном использовании примитивных операций над консолями в учебных целях.
Первая попытка обычно игнорирует возможное исчерпание стека. На каждом шаге вы сначала смотрите, находитесь ли вы в конце (затем возвращаете ноль), должен ли первый элемент быть отброшен (затем возвращать результат повторения для остальных), или если он должен быть сохранен (затем с результат рекурсии).
Если доступна оптимизация хвостового вызова, вы можете изменить ее, чтобы использовать аккумулятор. На каждом шаге вместо того, чтобы сначала возвращать, а затем обрабатывать, вы сохраняете сохраненное значение в аккумуляторе и передаете его в рекурсию. В конце вы не вернете ноль, а поменяете местами аккумулятор и вернете его.