使用set!
,我希望能够修改局部状态list
变量lst
,但只有一部分
例如,我想在内部列表中插入值:
((1 2) (4 5))
是
((1 2 3) (4 5))
我想做一些像set! (car lst) (append (car lst) 3)
但这似乎只修改了(car lst)
生成的临时变量。
我能想到的唯一方法是用新的期望值创建一个新的列表,并将lst
设置为新的列表,但这似乎是浪费和不必要的。有更好的方法吗?
try this:
(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!和set-car !
编辑:for球拍
使用可变列表:
(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
根据所使用的Scheme解释器的不同,您可能需要做更多的工作。例如,在Racket中,列表原语在默认情况下是不可可变的,因此您必须使用过程的可变版本:
(require scheme/mpair)
(define lst (mlist (mlist 1 2) (mlist 4 5)))
lst
(set-mcdr! (mcdr (mcar lst)) (mlist 3))
lst
Scheme中创建列表的标准习惯用法是将元素前置到前面,使用cons
,而不是尝试对列表中的最后一个cons单元格进行set-cdr!
。最后,当列表完成后,您可以使用reverse
以正确的顺序获取元素。这样,就不需要对列表本身进行修改。
如果你想创建列表(1 2 3)
piece:
- 从空列表、
()
和cons
1开始。这就是(1)
。 - 然后是
cons
2:(2 1)
- 然后
cons
3到列表:(3 2 1)
- 最后,当您完成构建列表时,将其反转:
(1 2 3)
你可能会问为什么这是"更好"。这是因为访问set-cdr!
的最后一对是一个O(n)操作;对于链表,元素不是随机访问的,而是在被访问的元素位置上是线性的。而cons
总是0(1)。
reverse
是一个O(n)操作,但只要您只在最后执行它(当您准备以正确的顺序构建列表时),而不是一直调用它,就不会对性能产生不利影响。