8

我正在尝试在 elisp 中实现我自己的深拷贝例程(因为类似的东西(setq newlist oldlist)似乎只给出了一个浅拷贝,并且(copy-sequence newlist oldlist)仍然newlist暴露于元素的任何变化oldlist

此外,如果有一个功能可以满足我的需求,我将无法找到它。

我的函数的定义是:

(defun deep-copy (iList oList)

    (setq oList (car iList))
    (setq counter (- (length iList) 1))
    (setq iList (cdr iList))
    (while (> counter 0)
        (setq oList (cons oList (car iList)))
        (setq iList (cdr iList))
        (setq counter (- counter 1) )))

之后,发生iList(1 2 3 4 5 6)事情oList是:(((((1 . 2) . 3) . 4) . 5) . 6) 即嵌套列表。

我尝试过引用、反引用、使用附加、切换oList(car iList)in的顺序(cons # #)、谷歌搜索解决方案,但我没有运气(错误或垃圾)。

除了对已经存在的可以执行我想要的功能的欢迎评论,代码中存在弱点的地方(我是 elisp 新手),有人可以告诉我如何正确地将元素添加到现有列表中吗?

这些示例往往是以下形式的变体:(cons 'pine '(fir oak maple)),其中'(fir oak maple)是一些硬编码列表

编辑:在过去的两个小时里,我一直在与自己作斗争(因为我在调用函数中注释掉了 oList,并且我一直在引用它的旧版本)。无论如何,最后交换oList然后(car iList)反转似乎可以解决问题(但肯定有更好的方法!?)即

(defun deep-copy (iList)
  (setq oList nil )
  (setq counter (- (length iList) 1))
  (while (>= counter 0)
    (setq oList (cons (car iList) oList) )
    (setq iList (cdr iList) )
    (setq counter (- counter 1) ))
  (reverse oList)
    )
4

2 回答 2

12

Elisp 有这个功能copy-tree。这是递归版本copy-sequence

例子

(let* ((orig '((1 2) (3 4)))
       (copy (copy-tree orig)))
  (setcdr (cadr copy) '(0))
  (list orig copy))
==> (((1 2) (3 4)) ((1 2) (3 0)))

在你的情况下,你可以写:

(setq oList (copy-tree iList))
于 2013-06-02T19:58:51.463 回答
11

使用copy-tree(示例假设您为required cl,为方便起见,但copy-tree它本身并不需要):

elisp> (setq list1 '(((1 2) (3 4)) 5 (6)))
(((1 2)
  (3 4))
 5
 (6))

elisp> (setq list2 (copy-sequence list1))
(((1 2)
  (3 4))
 5
 (6))

elisp> (setf (caar list2) 1)
1
elisp> list2
((1
  (3 4))
 5
 (6))

elisp> list1
((1
  (3 4))
 5
 (6))

elisp> (setq list1 '(((1 2) (3 4)) 5 (6)))
(((1 2)
  (3 4))
 5
 (6))

elisp> (setq list2 (copy-tree list1))
(((1 2)
  (3 4))
 5
 (6))

elisp> (setf (caar list2) 1)
1
elisp> list1
(((1 2)
  (3 4))
 5
 (6))

elisp> list2
((1
  (3 4))
 5
 (6))

我建议您阅读 Emacs 附带的 Elisp 介绍,而不是提供有关您的代码的提示:C-h i g (eintr) RET或其他介绍 Lisp 的书籍,例如Touretzky(后者适用于 Common Lisp,但是一个很好的介绍)。它会教你基础知识——例如,不仅仅是 setq函数定义等等。

但是给你一个例子,这里是copy-tree(或者,只是在你的 Emacs 中查看它:)的定义M-x find-function RET copy-tree RET

(defun copy-tree (tree &optional vecp)
  "Make a copy of TREE.
If TREE is a cons cell, this recursively copies both its car and its cdr.
Contrast to `copy-sequence', which copies only along the cdrs.  With second
argument VECP, this copies vectors as well as conses."
  (if (consp tree)
      (let (result)
    (while (consp tree)
      (let ((newcar (car tree)))
        (if (or (consp (car tree)) (and vecp (vectorp (car tree))))
        (setq newcar (copy-tree (car tree) vecp)))
        (push newcar result))
      (setq tree (cdr tree)))
    (nconc (nreverse result) tree))
    (if (and vecp (vectorp tree))
    (let ((i (length (setq tree (copy-sequence tree)))))
      (while (>= (setq i (1- i)) 0)
        (aset tree i (copy-tree (aref tree i) vecp)))
      tree)
      tree)))
于 2013-06-02T20:03:00.967 回答