我们没有得到nreconc
足够的使用。这是一个基于do
and的解决方案reconc
。这个想法是遍历列表,以相反的顺序从列表中累积元素,直到到达需要替换的元素的位置。然后你把这些位粘在一起。也就是说,您反转您一直在积累的列表,并将其附加到由新元素和尾部构建的列表中。
(defun add (number index list)
(do ((head '() (list* (first tail) head))
(tail list (rest tail))
(index index (1- index)))
((zerop index)
(nreconc head (list* (+ number (first tail))
(rest tail))))))
CL-USER> (add 5 2 '(3 1 4 6 7))
(3 1 9 6 7)
值得看看这些值如何随时间变化。让我们考虑一个具有更多数字的示例,并查看每次迭代中head
、tail
和的值:index
CL-USER> (add 90 5 '(0 1 2 3 4 5 6 7 8 9))
(0 1 2 3 4 95 6 7 8 9)
head: ()
tail: (0 1 2 3 4 5 6 7 8 9)
index: 5
head: (0)
tail: (1 2 3 4 5 6 7 8 9)
index: 4
head: (1 0)
tail: (2 3 4 5 6 7 8 9)
index: 3
head: (2 1 0)
tail: (3 4 5 6 7 8 9)
index: 2
head: (3 2 1 0)
tail: (4 5 6 7 8 9)
index: 1
head: (4 3 2 1 0)
tail: (5 6 7 8 9)
index: 0
一旦我们得到0
,我们可以通过将其与 相加并将其放在一起来获得最终结果的其余部分,即number
(car tail)
(cdr tail)
(list* (+ (car tail) number) (cdr tail)
产生
(95 6 7 8 9)
然后使用nreconc
取(4 3 2 1 0)
和(95 6 7 8 9)
取(0 1 2 3 4 95 6 7 8 9)
,即
(nreconc (list 4 3 2 1 0) '(95 6 7 8 9))
;=> (0 1 2 3 4 95 6 7 8 9)
现在,如果由于某种原因您不能使用do
,例如,这是一个家庭作业,那么该跟踪仍应为您提供足够的信息来编写带有累加器的直接递归版本。但是,无论如何,您仍然需要能够reverse
(或nreverse
)一个列表,以及append
(或nconc
)一些列表在一起(或,组合,revappend
或nreconc
)。