连接列表并将结果返回到第一个参数

时间:2018-06-13 15:46:28

标签: list functional-programming append concatenation common-lisp

我想知道在Common Lisp中执行类似操作的最有效(algrotihmically)和可读方式是什么:

(setq result-list (append result-list small-list))

也就是说,(append-destructively result-list small-list)之类的内容会确保result-list包含连接列表吗?

我这样做是为了提高可读性,但在(功能)编程实践方面它是一个好主意吗?

3 个答案:

答案 0 :(得分:4)

如果你必须在同一个清单上一遍又一遍地做, tail-wagging可能是最好的解决方案(我从Edi Weitz的书中学到的):

(defparameter *l* (list 'a 'b 'c 'd 'e 'f))

*l*一个名字的最后一个单元格

(defparameter *tail* (last *l*))

现在,(cdr *tail*)是列表的最后一个元素:'()。 假设您要将(list 'g 'h 'i)添加到其结尾。 将(setf)分配给(cdr *tail*),这是列表cons的最后一个'() - 单元格:*l*, 并将(setf)新的最后一个元素重新分配给 tail

(setf (cdr *tail*) (list 'g 'h 'i)
      *tail*       (last *tail*))

现在,*l*被变异以包含第二个列表。 和*tail*命名此新列表的最后一个cons单元格。

*l*
;; (a b c d e f g h i)
*tail*
;; (i)

下一次,当*tail*必须通过列表进行扩展时,您不必再次遍历所有列表,但只能分配给cdr *tail*待附加列表然后修改原始列表。

顺便说一句,在考虑tailp时,我偶然发现了tail-wagging

答案 1 :(得分:3)

destructive append is called nconc

但请注意,需要

(setf result-list (nconc result-list small-list))

因为如果result-listnil,那么(nconc result-list small-list)small-listresult-list未经修改。

需要注意的另一个问题是nconcappend都是 {em>线性 result-list长度,所以这是一个非常好的方法 存储了大量数据。

答案 2 :(得分:2)

看看你的问题,我会猜测你想要什么,并提出一些提示,如果你想反复扩展一个列表,但又不想一次又一次地扫描它。

如果您处于循环中,可以使用collectappendnconc

(defun nconcat (lists)
  (loop for list in lists nconc list))

如果您想在更一般的设置中执行此操作,我们的想法是跟踪列表的结尾,以便追加只需要扫描短列表。例如:

(defun nconcat (lists)
  (let* ((result-ref (list nil))
         (end result-ref))
    (mapc
      (lambda (list)
        (setf (cdr end) list
              end (last end)))
      lists)
    (cdr result-ref)))