Common Lisp:如何在没有给定列表的第n个元素的情况下返回列表?

时间:2012-02-25 14:33:43

标签: lisp common-lisp

我有一个问题,如何返回没有给定列表的第n个元素的列表?例如,给定列表:(1 2 3 2 4 6),给定n = 4,在这种情况下,返回列表应为(1 2 3 4 6)

9 个答案:

答案 0 :(得分:8)

一个简单的递归解决方案:

(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个或更多元素,在这种情况下,它将返回一个新列表,其中包含与提供的元素相同的元素。

答案 1 :(得分:7)

使用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 :(得分:2)

这是一个有趣的方法。它用新符号替换列表的第n个元素,然后从列表中删除该符号。我没有考虑过它的效率如何(in)!

(defun remove-nth (n list)
    (remove (setf (nth n list) (gensym)) list))

答案 3 :(得分:1)

稍微更通用的功能:

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

编辑:塞缪尔评论的应用评论。

答案 4 :(得分:1)

对于你那里的所有haskellers,没有必要扭曲你的大脑:)

(defun take (n l)
  (subseq l 0 (min n (length l))))
(defun drop (n l)
  (subseq l n))
(defun remove-nth (n l)
  (append (take (- n 1) l)
      (drop n l)))

答案 5 :(得分:0)

我可怕的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。

答案 6 :(得分:0)

更简单的解决方案如下:

(defun remove-nth (n lst)
    (append (subseq lst 0 (- n 1)) (subseq lst n (length lst)))
)

答案 7 :(得分:0)

破坏性版本,原始列表将被修改(除非n <1),

(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函数。

答案 8 :(得分:0)

(loop :for i :in '(1 2 3 2 4 6) ; the list
              :for idx :from 0
              :unless (= 3 idx) :collect i) ; except idx=3
;; => (1 2 3 4 6)

循环宏在Lisp编译器和宏扩展器生成的代码方面非常有用和有效。

运行测试并在代码段上方应用宏展开。