我有一个事物列表(我称之为 L)、一个索引(N)和一个新事物(NEW)。如果我想用 NEW 替换 L 在 N 的东西,最好的方法是什么?我是否应该将子列表增加到 N 并从 N 到列表末尾,然后使用列表将第一部分 NEW 和最后一部分的新列表粘合在一起?还是有更好的方法来做到这一点?
10 回答
(setf (nth N L) NEW)
应该做的伎俩。
你打算多久做一次;如果你真的想要一个数组,你应该使用一个数组。否则,是的,创建一个由前 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)))))
(setf (nth N L) T)
如果您要做的是“破坏性”修改,即实际更改现有列表,则这是最清晰,最简洁,最快的方法。它不分配任何新内存。
我只是尝试修复 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 <= n <= 长度(列表)- 1
hazzen 的建议很好(使用数组),因为您可能想做很多这些破坏性的更新,而列表在随机访问时效率很低。最简单的方法
(setq A (make-array 5) :initial-contents '(4 3 0 2 1))
(setf (elt 2 A) 'not-a-number)
其中 A 是一个数组(尽管elt
适用于任何序列)。
但是,如果您必须具备功能,那就是
- 您想保留旧列表和新列表
- 您希望新旧共享尽可能多的内存。
然后你应该使用与 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 版本,有用的是你正在使用的。
使用 [REPLACE][1] (我使用 X 而不是你的 T 因为 T 是 Lisp 中的真实值):
(replace L (list X) :start1 N)
[1]:http ://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm替换
听起来你想要 rplaca 或替换。请参阅http://www.lispworks.com/documentation/HyperSpec/Body/f_rplaca.htm或http://www.lispworks.com/documentation/HyperSpec/Body/f_replac.htm#replace
很快你就可以用 JS 在list-replace上做到这一点
正如其他人所指出的,显而易见的解决方案很慢并且使用内存。如果可能,您应该尝试推迟替换元素,直到您需要对列表执行另一个元素操作,例如(loop for x in list do ...)
.
这样,您将摊销掉 consing(内存)和迭代(cpu)。
(defun replace-nth-from-list (list n elem)
(cond
((null list) ())
(t (append (subseq list 0 n) elem (subseq list (+ 1 n)(length list))))))