我有一个功能,可以将列表中的每个项目加倍:
(defun double (L)
(cond
((atom L) nil)
(t (cons (car L) (cons (car L ) (double (cdr L))))) ) )
(double '(a b c )) => (a a b b c c)
如何在将函数调用cons
的次数除以2时完成相同的结果? (即在前面的例子中,它调用cons
6次。我怎么能只用3次呢?)
谢谢!
编辑2,在jkiiski的评论之后,似乎现在有效:
(defun double2 (L)
(cond
((atom L) nil)
(t (setf
(cdr L)
(cons (car L ) (double2 (cdr L))))
L) ) )
(double2 (list 'a 'b 'c)) => (a a b b c c)
答案 0 :(得分:2)
这是另一种方法,没有递归。请注意,这个答案假设您正在做一个功课并试图找到一种方法来避免创建一个新的列表,这是最简单的解决方案。实际上,您只需在collect
中使用loop
两次,就像Sylwester演示的那样。这里破坏性地修改了原始输入列表。
假设您的原始list
为(1 2 3)
。而不是消耗
元素你自己,你可以调用(copy-list list)
来执行
需要的金额。这就是你需要考虑的所有内存
分配。然后,你“只”需要将所有缺点单元格交错
获得所需的重复。
保持给定的list
变量,并定义两个变量
迭代两个列表:
current = (1 2 3) ;; original
fresh = (1 2 3) ;; copy
从图形上看,您希望将CDR更改为“将”现有的cons-cells“线程化”在一起。首先,两个列表都是这样的:
current ( 1 . x-)-->( 2 . x-)-->...
fresh ( 1 . x-)-->( 2 . x-)-->...
但你想拥有:
current ( 1 . x ) ( 2 . x )
| ^ |
V | V
fresh ( 1 . x ) ( 2 . ...)
更正式地说,在每个步骤的开头,当您的列表不为空时,上述变量可以按如下方式分解:
current = (chead . ctail)
fresh = (fhead . ftail)
您希望current
的尾部指向fresh
cons-cell,并使fresh
的尾部指向ctail
。
完成交错单元格后,变量应绑定如下:
current = (chead . (fhead . ctail))
fresh = ftail
然后,你可以在current
下降两次,最后:
current = ctail
fresh = ftail
从这里开始,您可以继续使用其他两个列表。注意
list
仍然包含您给出的原始cons单元格
输入。
(defun double-loop (list)
(loop
with fresh = (copy-list list) ;; cursor to new cons cells
with current = list ;; cursor to current cell
while fresh ;; stop when fresh is nil
do (print (list list current fresh)) ;; for debugging
(rotatef (cdr fresh) (cdr current) fresh) ;; change CDRs, rebind fresh
(setf current (cddr current)) ;; update CURRENT
finally (return list))) ;; LIST points to head of result
我正在使用ROTATEF
来连接cons细胞:
(rotatef (cdr fresh) (cdr current) fresh)
fresh
的值放在(cdr current)
中,其前一个值本身位于(cdr fresh)
,原始值为fresh
其值最终成为绑定到CL-USER> (double-loop (list 0 1 2 3))
((0 1 2 3) (0 1 2 3) (0 1 2 3))
((0 0 1 2 3) (1 2 3) (1 2 3))
((0 0 1 1 2 3) (2 3) (2 3))
((0 0 1 1 2 2 3) (3) (3))
=> (0 0 1 1 2 2 3 3)
的新值。
以下是示例跟踪输出:
hive-import
答案 1 :(得分:1)
在jkiiski的评论之后,似乎现在有效:
Object d = new Dog();
((Dog) d).print();
d.getClass().getMethod("print").invoke(d);