Common Lisp: как вернуть список без n-го элемента данного списка?
у меня вопрос, как вернуть список без n-го элемента данного списка? Е. Г., приведенный список: (1 2 3 2 4 6)
, а с учетом n = 4
в этом случае возврат денежных средств должен быть (1 2 3 4 6)
.
7 ответов
простое рекурсивное решение:
(defun remove-nth (n list)
(declare
(type (integer 0) n)
(type list list))
(if (or (zerop n) (null list))
(cdr list)
(cons (car list) (remove-nth (1- n) (cdr list)))))
это будет общий хвост, за исключением случая, когда список имеет n
или более элементов, в этом случае он возвращает новый список с теми же самыми элементами, так как одна.
используя remove-if
:
(defun foo (n list)
(remove-if (constantly t) list :start (1- n) :count 1))
butlast
/nthcdr
решение (исправлено):
(defun foo (n list)
(append (butlast list (1+ (- (length list) n))) (nthcdr n list)))
или, может быть, более читаемым:
(defun foo (n list)
(append (subseq list 0 (1- n)) (nthcdr n list)))
используя loop
:
(defun foo (n list)
(loop for elt in list
for i from 1
unless (= i n) collect elt))
немного более общая функция:
(defun remove-by-position (pred lst)
(labels ((walk-list (pred lst idx)
(if (null lst)
lst
(if (funcall pred idx)
(walk-list pred (cdr lst) (1+ idx))
(cons (car lst) (walk-list pred (cdr lst) (1+ idx)))))))
(walk-list pred lst 1)))
который мы используем для реализации желаемого remove-nth:
(defun remove-nth (n list)
(remove-by-position (lambda (i) (= i n)) list))
и ссылки:
(remove-nth 4 '(1 2 3 2 4 6))
Edit: примененные замечания из комментария Сэмюэля.
вот интересный подход. Он заменяет N-й элемент списка с новым символом, а затем удаляет этот символ из списка. Я не рассматривал, как (в)эффективно это, хотя!
(defun remove-nth (n list)
(remove (setf (nth n list) (gensym)) list))
мое ужасное решение elisp:
(defun without-nth (list n)
(defun accum-if (list accum n)
(if (not list)
accum
(accum-if (cdr list) (if (eq n 0) accum (cons (car list) accum))
(- n 1))))
(reverse (accum-if list '() n)))
(without-nth '(1 2 3) 1)
должен быть легко переносимым на общий Lisp.
гораздо более простым решением будет следующее.
(defun remove-nth (n lst)
(append (subseq lst 0 (- n 1)) (subseq lst n (length lst)))
)
разрушительная версия, исходный список будет изменен (за исключением случаев, когда n
(defun remove-nth (n lst)
(if (< n 1) (cdr lst)
(let* ((p (nthcdr (1- n) lst))
(right (cddr p)))
(when (consp p)
(setcdr p nil))
(nconc lst right))))
это elisp, но я думаю, что это стандартные функции lispy.