CommonLisp:如何返回不包含给定列表第n个元素的列表?
我有一个问题,如何返回没有给定列表第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
(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)))