Vincent,Gishu和Jerry暗示您需要检查项目是否已添加到结果列表中,而Derek暗示您可以在看到项目重复时修改原始列表。
阅读的功能adjoin
和remove
这里的文档:
http://www.lispworks.com/documentation/HyperSpec/Body/f_adjoin.htm
http://www.lispworks.com/documentation/HyperSpec/Body/f_rm_rm.htm
的HyperSpec是一个非常有用的参考,将其添加书签。
这两个函数不会修改它们的参数,而是将结果作为新列表返回。还有其他的功能可以修改他们的论点,因此可能会更有效率,但在这一点上,也许你不应该担心它们。
好的,我希望在写这篇文章的时候你已经明白了。如果不是,继续尝试,那是你真正学习的唯一方法。
现在我想谈谈另一种方法,那就是通过递归调用来实现结果。
我们的功能repeated
会做什么,但调用辅助功能repeatedr
这将做实际工作,传递给它的初始空的结果'()
:
(defun repeated (lst)
(repeatedr lst '()))
现在,让我们定义的辅助函数,它接收两个参数:搜索重复项的列表以及我们将累积重复项的结果列表。
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
当条件(member (first lst) (rest lst))
成立,我们将毗第一项至result
,而毗邻的将被传递给递归调用作为第二个参数的结果;否则我们只是将result
按原样传递给递归调用。
当列表最后为空时(if (null lst)
我们将返回result
。
> (repeated '(a a b a b c))
(B A)
注意,结果是(B A)
,也许你期待它是(A B)
。尝试使用笔和纸跟随递归调用的执行和每次调用时的参数值,这将是一个很好的练习,并且您必须使用adjoin
来了解其行为。如果你想要得到的结果相反,你可以修改的功能是这样的:
(defun repeatedr (lst result)
(if (null lst)
(reverse result)
(if (member (first lst) (rest lst))
(repeatedr (rest lst) (adjoin (first lst) result))
(repeatedr (rest lst) result))))
这反向 S中的结果,当递归结束。
现在,在下一步之前如何从列表中删除重复的元素?我们可以写我们的功能是这样的:
(defun repeatedr (lst result)
(if (null lst)
result
(if (member (first lst) (rest lst))
(repeatedr (remove (first lst) lst) (cons (first lst) result))
(repeatedr (rest lst) result))))
尝试在REPL与remove
玩:
> (remove 'a '(a b c d a e f b a d))
(B C D E F B D)
请注意,我们不再毗荷兰国际集团的结果,而不是我们只是创建一个新的“cons cell”与(cons (first lst) result)
。 cons
和adjoin
可以做同样的事情,但只有当它不在列表中时,adjoin才会添加该值。
希望这给你一些玩的东西。
链式IF形式可以更好地转换为COND。 – Svante 2009-12-08 16:59:18