使用set修改列表的一部分?

时间:2011-10-27 01:13:50

标签: scheme racket

使用set!我希望能够修改本地状态list变量lst,但只能修改其中的一部分

例如,我想在内部列表中插入值:

((1 2) (4 5))

变为

((1 2 3) (4 5))

我希望能够执行set! (car lst) (append (car lst) 3)

之类的操作

但这似乎只修改(car lst)生成的临时变量。

我能想到的唯一方法是创建一个包含新所需值的新列表,并将lst设置为新列表,但这似乎是浪费和不必要的。有没有更好的方法呢?

3 个答案:

答案 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)操作,但只要你只在最后(当你准备以正确的顺序构建列表时),而不是全部调用它时间,这不会对绩效产生不利影响。