替换 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 适用于任何序列)。

The 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 中复制结构列表

Common Lisp:在 first、rest、last 中解构列表(如 Python 可迭代解包)

从clojure中的普通lisp替换(null x)函数的惯用方法

Common Lisp 中的整数除法

Common Lisp 中的本地状态