替换 Common Lisp 列表中的项目?
Posted
技术标签:
【中文标题】替换 Common Lisp 列表中的项目?【英文标题】:Replace an item in a list in Common Lisp? 【发布时间】:2010-09-15 07:35:56 【问题描述】:我有一个事物列表(我称之为 L)、一个索引(N)和一个新事物(NEW)。如果我想用 NEW 替换 L 在 N 的东西,最好的方法是什么?我是否应该让子列表达到 N 并从 N 到列表的末尾,然后使用列表将第一部分 NEW 和最后一部分的新列表粘合在一起?或者有更好的方法吗?
【问题讨论】:
【参考方案1】:(setf (nth N L) NEW)
应该可以解决问题。
【讨论】:
是的,除了你不能在 common lisp 中使用 t 作为变量名,因为它也是真值符号。 更新了答案(和问题)以使用NEW
作为替换项,而不是 T
一个名为“T”的符号很好,它不能是属于“COMMON-LISP”包的那个。 :)【参考方案2】:
您打算多久执行一次;如果你真的想要一个数组,你应该使用array。否则,是的,创建一个由前 N 个元素、新元素和尾部的副本组成的新列表的函数就可以了。我不知道我脑子里有一个内置函数,但我有一段时间没有用 Lisp 编程了。
这是 Scheme 中的一个解决方案(因为我知道它比 Common Lisp 更好,并且有一个解释器来检查我的工作):
(define (replace-nth list n elem)
(cond
((null? list) ())
((eq? n 0) (cons elem (cdr list)))
(#t (cons (car list) (replace-nth (cdr list) (- n 1) elem)))))
【讨论】:
您在数组上的链接指向 CLtL,一个 Common Lisp 文本。但是您的文本是方案代码。这个问题不清楚它想要什么方言(尽管它被标记为 common-lisp)。如果您注意到数组适用于 CL 而您的示例代码适用于 Scheme,这将有所帮助。 非常正确;更改以反映这一点。【参考方案3】:(setf (nth N L) T)
是最清晰、最简洁、最快的方法,如果您想做的是“破坏性”修改,即实际更改现有列表。它不会分配任何新内存。
【讨论】:
【参考方案4】:我只是尝试修复 hazzen 的代码:
(define (replace-nth list n elem)
(cond
((null? list) ())
((eq? n 0) (cons elem list))
(#t (cons(car list) (replace-nth (cdr list) (- n 1) elem)))))
> (replace-nth (list 3 2 9 2) 2 8)
(3 2 8 9 2)
此代码在列表中插入了新元素。如果我们想替换一个元素:
(define (replace-nth list n elem)
(cond
((null? list) ())
((eq? n 0) (cons elem (cdr list)))
(#t (cons(car list) (replace-nth (cdr list) (- n 1) elem)))))
> (replace-nth (list 3 2 9 2) 2 8)
(3 2 8 2)
0
【讨论】:
【参考方案5】:hazzen 的建议很好(使用数组),因为您可能想要进行大量此类破坏性更新,而列表在随机访问时效率非常低。最简单的方法
(setq A (make-array 5) :initial-contents '(4 3 0 2 1))
(setf (elt 2 A) 'not-a-number)
其中 A 是一个数组(尽管elt
适用于任何序列)。
elt
definition, with examples of setf
。
The make-array
definition, with examples
但是,如果您必须具有功能性,那就是
-
您希望同时保留旧列表和新列表
您希望新旧共享尽可能多的内存。
那么你应该使用与 hazzen 的代码等效的 Common Lisp:
(defun replace1 (list n elem)
(cond
((null list) ())
((= n 0) (cons elem list))
(t (cons (car list) (replace1 (cdr list) (1- n) elem)))))
这看起来很慢,因为它是,这可能是它没有包含在标准中的原因。
hazzen 的代码是 Scheme 版本,有用的是你正在使用的。
【讨论】:
感谢您提供 Common Lisp 中的代码,但是(= n 0)
条件中有一个错误:它应该返回 (cons elem (cdr list))
而不是 (cons elem list)
。【参考方案6】:
听起来您想要 rplaca 或替换。见http://www.lispworks.com/documentation/HyperSpec/Body/f_rplaca.htm或http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm#replace
【讨论】:
可能太麻烦了。 (setf (nth N L) T),正如 l0st3d 建议的那样,用最少的代码做正确的事。【参考方案7】:使用 [REPLACE][1](我使用 X 而不是您的 T,因为 T 是 Lisp 中的真实值):
(replace L (list X) :start1 N)
[1]:http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm替换
【讨论】:
正是我需要的!此答案应设置为接受的答案!【参考方案8】:您可以在list-replace 上使用 JS 快速完成此操作
【讨论】:
【参考方案9】:正如其他人所指出的那样,显而易见的解决方案很慢并且使用内存。如果可能,您应该尝试推迟替换元素,直到您需要对列表执行另一个元素操作,例如(loop for x in list do ...)
.
这样,您将摊销掉 consing(内存)和迭代(cpu)。
【讨论】:
【参考方案10】:(defun replace-nth-from-list (list n elem)
(cond
((null list) ())
(t (append (subseq list 0 n) elem (subseq list (+ 1 n)(length list))))))
【讨论】:
假设elem
是一个列表,这可能不一定是真的。以上是关于替换 Common Lisp 列表中的项目?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用依赖于包装它的较短列表的 map 循环较长的列表以将某些函数应用于 Common Lisp 中的较长列表?
Common Lisp:在 first、rest、last 中解构列表(如 Python 可迭代解包)