CommonLisp:如何返回不包含给定列表第n个元素的列表?

CommonLisp:如何返回不包含给定列表第n个元素的列表?,lisp,common-lisp,Lisp,Common Lisp,我有一个问题,如何返回没有给定列表第n个元素的列表?例如,给定列表:(1 2 3 2 4 6),并且给定n=4,在这种情况下,返回列表应该是(1 2 3 4 6)我的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 l

我有一个问题,如何返回没有给定列表第n个元素的列表?例如,给定列表:
(1 2 3 2 4 6)
,并且给定
n=4
,在这种情况下,返回列表应该是
(1 2 3 4 6)
我的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)
(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)))))

应易于移植到通用Lisp。

稍微通用一点的功能:

(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)))
我们使用它来实现所需的第n步:

(defun remove-nth (n list)
  (remove-by-position (lambda (i) (= i n)) list))
以及调用:

(remove-nth 4 '(1 2 3 2 4 6))

编辑:应用Samuel评论中的注释。

使用
删除if

(defun foo (n list)
  (remove-if (constantly t) list :start (1- n) :count 1))
butlast
/
nthcdr
解决方案(已更正):

或者,更具可读性:

(defun foo (n list)
  (append (subseq list 0 (1- n)) (nthcdr n list)))
使用
循环

(defun foo (n list)
  (loop for elt in list
        for i from 1
        unless (= i n) collect elt))

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

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

下面是一个有趣的方法。它用新符号替换列表的第n个元素,然后从列表中删除该符号。不过,我还没有考虑它的效率有多高

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

一个更简单的解决方案如下所示

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

对于破坏性版本,将修改原始列表(n<1时除外)

(取消删除第n个(第n个)
(如果(
这是elisp,但我认为它们是标准的lispy函数。

(循环:for I:in'(1 2 3 2 4 6);列表
:对于idx:从0开始
:除非(=3 idx):收取i);除idx=3外
;; => (1 2 3 4 6)
循环宏在lisp编译器和宏扩展器生成代码方面非常有用和有效


测试运行并应用上面的代码片段进行宏扩展。

对于所有Haskeller,不需要绞尽脑汁:)


如果这是作业,请添加“作业”标记。@dasblinkenlight Lisp作业?我想not@SethCarnegie顺便说一句,有趣的是,我是如何在一个错误的解决方案中得到两张赞成票的。在与Haskell几乎完全合作了几个月之后,我最初在
butlast
解决方案中使用了
butlast
take
。(按照
take n xs++drop(n+1)xs
的思路思考)由于我最近一直在用Haskell写作,我在心里做了同样的事情,所以我比你高得多。。。oops@jcc333伟大的人都会犯同样的错误不管怎样,它现在已经被纠正了–没有造成任何伤害。或者使用NCOC:
(defun nfoo(n ls)(NCOC(butlast…)
)。但是缺少对
n>(长度ls)
案例的检查。只有
循环
版本在运行。@WillNess是的,如果要在库中使用,或者在不能保证正确输入的情况下,可以添加
(断言)(在常见的Lisp中,本地函数是通过FLET和标签引入的。+1:我编写了基于过程
DO
的版本,手动构建结果,结果是(在SBCL上)与
remove if
方法相比,速度快了4倍,考虑也不充分,但这更干净,性能也一样…@6502,最初的问题并不是说是否禁止修改输入列表,或者输出列表是否应该共享结构。我通常更喜欢我的函数是非破坏性的,共享结构,但我在这个问题上,我看不到任何禁止修改输入的东西。C和Java程序员可能会发现这是一件很自然的事情。在某些情况下,共享尾部可能是一种负担,而不是一种资产。顺便说一下:虽然我更喜欢默认使用非破坏性功能,但从某种意义上说,破坏性版本更为普遍解决方案。您可以通过复制其参数将任何破坏性操作转换为非破坏性操作–但是,使非破坏性函数具有破坏性通常需要重写。(这只是一个旁注,而不是将破坏性操作作为默认操作的参数。)我同意这一点“内部破坏,外部纯粹”的函数编写方法(比如我的
do
/
(setf(cdr x)y)
)不会按组成进行缩放。我不是普通的Lisp专家,但正如问题所述(“返回一个没有给定列表第n个元素的列表”)我认为破坏性操作会令人惊讶……但可能是我(例如,我过去被破坏性的
sort
咬过,没有被命名为
sorrt
)。@SamuelEdwinWard引用:“例如,给定列表:(12346),给定n=4,在这种情况下,返回列表应该是(12346)。“使用基于0的索引,结果必须是
(1 2 3 2 6)
,这也是您的代码生成的。最后一句应该是“小于
n
元素”。小东西,按1等分。:)有趣的是,这是我以前想要的。我建议将您的
remove nth
重命名为…其他…
remove by position
?并定义remove nth
(defun remove nth(n list)(remove by position(lambda(I)(=in))列表)
(defun delete nth(n list)(delete(setf(nth n list)(gensym))请解释你的答案将如何帮助解决问题,不要只给出代码答案而没有上下文对不起,我想问题已经给出了上下文。
(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)))