使用set!
我希望能够修改本地状态list
变量lst
,但只能修改其中的一部分
例如,我想在内部列表中插入值:
((1 2) (4 5))
变为
((1 2 3) (4 5))
我希望能够执行set! (car lst) (append (car lst) 3)
但这似乎只修改(car lst)
生成的临时变量。
我能想到的唯一方法是创建一个包含新所需值的新列表,并将lst
设置为新列表,但这似乎是浪费和不必要的。有没有更好的方法呢?
答案 0 :(得分:2)
试试这个:
(define lst (list (list 1 2) (list 4 5)))
lst
> ((1 2) (4 5))
(set-cdr! (cdar lst) (list 3))
lst
> ((1 2 3) (4 5))
修改缺点/列表时,你应该使用set-cdr!和定车!
编辑:用于球拍
使用可变列表:
(require racket/mpair)
(define lst (mlist (mlist 1 2) (mlist 4 5)))
lst
> (mcons (mcons 1 (mcons 2 '())) (mcons (mcons 4 (mcons 5 '())) '()))
(set-mcdr! (mcdr (mcar lst)) (list 3))
> (mcons (mcons 1 (mcons 2 #<promise:temp2>)) (mcons (mcons 4 (mcons 5 '())) '()))
lst
答案 1 :(得分:0)
根据您使用的Scheme的解释器,您可能需要做更多的工作。例如,在Racket中,默认情况下列表基元不可变,并且您必须使用过程的可变版本:
(require scheme/mpair)
(define lst (mlist (mlist 1 2) (mlist 4 5)))
lst
(set-mcdr! (mcdr (mcar lst)) (mlist 3))
lst
答案 2 :(得分:-1)
Scheme中用于创建列表零碎的标准习惯是使用cons
将元素添加到前面,而不是尝试set-cdr!
列表中的最后一个cons单元格。最后,当您的列表完成后,您可以使用reverse
以正确的顺序获取元素。这样,本身不需要列表突变。
因此,如果您尝试创建列表(1 2 3)
零碎:
()
和cons
1开始。这会为您提供(1)
。cons
2到列表:(2 1)
cons
3到列表中:(3 2 1)
(1 2 3)
你可能会问为什么这是“更好”。这是因为访问最后一对set-cdr!
是一个O(n)操作;对于链表,元素不是随机访问,而是在被访问的元素位置上是线性的。然而,cons
总是O(1)。
reverse
是一个O(n)操作,但只要你只在最后(当你准备以正确的顺序构建列表时),而不是全部调用它时间,这不会对绩效产生不利影响。