Common Lisp: Как вернуть список без n-го элемента данного списка? - PullRequest
6 голосов
/ 25 февраля 2012

У меня вопрос, как вернуть список без n-го элемента данного списка?Например, данный список: (1 2 3 2 4 6) и данный n = 4, в этом случае список возврата должен быть (1 2 3 4 6).

Ответы [ 7 ]

8 голосов
/ 25 февраля 2012

Простое рекурсивное решение:

(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 или более элементов, и в этом случае он возвращает новый список с тем жеэлементы как предоставленные.

7 голосов
/ 25 февраля 2012

Использование 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))
2 голосов
/ 14 марта 2012

Вот интересный подход. Он заменяет n-й элемент списка новым символом, а затем удаляет этот символ из списка. Я не думал, насколько (не) эффективно это, хотя!

(defun remove-nth (n list)
    (remove (setf (nth n list) (gensym)) list))
1 голос
/ 25 февраля 2012

Немного более общая функция:

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

Редактировать: Прикладные замечания из комментария Самуила.

0 голосов
/ 20 июня 2016

Деструктивная версия, исходный список будет изменен (кроме случаев, когда n <1), </p>

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

0 голосов
/ 26 октября 2012

Гораздо более простое решение будет следующим:

(defun remove-nth (n lst)
    (append (subseq lst 0 (- n 1)) (subseq lst n (length lst)))
)
0 голосов
/ 25 февраля 2012

Мое ужасное решение 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)

Должно быть легко переносимым на Common Lisp.

...