使用set修改列表的一部分



使用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)操作,但只要您只在最后执行它(当您准备以正确的顺序构建列表时),而不是一直调用它,就不会对性能产生不利影响。

最新更新