尝试创建列表的副本。我使用了copy-list但是这会修改原始列表,因此我无法使用copy-list和copy-tree无法正常工作。任何建议将不胜感激
(defun switch-var (var list_a)
(let ((temp (copy-list list_a)))
(setf (cdr (assoc var temp)) (not (cdr (assoc var temp))))temp))
例如在lisp中,我将创建一个列表,然后调用switch-var
(setf *list_a* '((A NIL) (B T) (C T) (D NIL)))
* (switch-var ’b *list_a*)
;I will get this which is ok
((A NIL) (B NIL) (C T) (D NIL))
;but if i call it again
* (switch-var ’b *list_a*)
;I will get this which is not ok
((A NIL) (B T) (C T) (D NIL))
;so techincally I do not want to modify the original list_a
;in the function I just want to modify the temp
答案 0 :(得分:0)
您的示例代码存在多个问题。
评论中已经指出了第一个; copy-list
复制给定的列表,但不复制该列表的元素。这一事实意味着您应该使用copy-tree
代替。
第二个是setf没有修改你认为你正在修改的地方。
使用您的示例代码,当我第一次评估(switch-variable ’b *list_a*)
时,结果是列表((A NIL) (B) (C T) (D NIL))
,我们可以注意到它与列表((A NIL) (B NIL) (C T) (D NIL))
不同
当我第二次评估(switch-variable ’b *list_a*)
时,结果是列表((A NIL) (B . T) (C T) (D NIL))
,我们可以注意到它与列表((A NIL) (B T) (C T) (D NIL))
不同
根据(B T)
,考虑列表(B . T)
与cons
对之间的差异。第一个可以通过评估(cons 'b (cons t nil))
来构建。第二个可以通过评估(cons 'b t)
来构建。这应该会引导您直接解决问题,并解决问题。
在您的评论中提到您使用copy-tree
时仍然遇到问题,您可以通过执行以下操作确认copy-tree
按预期正常工作:
CL-USER> (defvar *test-alist* '((a nil) (b t) (c t) (d nil)))
*TEST-ALIST*
CL-USER> (defun lists-share-p (list1 list2)
(intersection list1 list2 :test #'eq))
LISTS-SHARE-P
CL-USER> (lists-share-p *test-alist* (copy-list *test-alist*))
((D NIL) (C T) (B T) (A NIL))
CL-USER> (lists-share-p *test-alist* (copy-tree *test-alist*))
NIL
当我遇到的问题开始看起来可能是在语言提供的函数/表单中工作不太正确时,做上述小型简单测试以确认或纠正我对这些的理解非常有用函数/表单,因为它们通常会导致对函数/表单的功能有正确的理解,或者导致我在代码中出错。您也可以自己发现这种情况。
答案 1 :(得分:0)
最好使用循环在一次传递中复制和修改列表。或者地图,但我更喜欢循环。
(defparameter *foo* '((a . nil)
(b . t)
(c . t)
(d . nil)))
(defun switch-variable (var list)
(loop
for (name . val) in list
collecting (cons name
(if (eql name var)
(not val)
val))))
(switch-variable 'b *foo*)
;=> ((A) (B) (C . T) (D))
(switch-variable 'b *foo*)
;=> ((A) (B) (C . T) (D))
使用cons单元代替变量列表更有效。它在打印时不会显示NIL
,但这只是视觉效果(值仍为NIL
)。
答案 2 :(得分:0)
就配对而言,你所拥有的基本上是以下内容(我试图接近" cons盒"但是在相同的空间中,我已经完成了内部列表列表):
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
v v v v
(A NIL) (B T) (C T) (D NIL)
运行copy-list
后,您拥有以下内容(top是原始版,bottom是copy-list
的返回值):
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
v v v v
(A NIL) (B T) (C T) (D NIL)
^ ^ ^ ^
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
然后,您将浏览并修改复制的顶级列表:
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
v v v v
(A NIL) (B NIL) (C T) (D NIL)
^ ^ ^ ^
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
此时,您已修改了其中一个您尚未复制的内部列表。如果您使用copy-tree
代替,则您会遇到以下情况(top是原始,bottom是copy-tree
返回):
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
v v v v
(A NIL) (B T) (C T) (D NIL)
(A NIL) (B T) (C T) (D NIL)
^ ^ ^ ^
[ | . --]--> [ | . --]--> [ | . --]--> [ | . --]--> NIL
此时,内部列表也会被复制,您可以根据需要对其进行破坏性修改,而无需修改原始列表。