我在研究Lisp(主要是递归)的几周内。到目前为止,我一直在处理足够简单的函数来测试递归的基本知识(car,cdr,cond,remove,nth等)。我偶然发现了一个我无法做对的简单问题。问题是:
编写一个带有两个参数的函数remove-nth:
(defun remove-nth (n l)
)
其中n是非负整数,list是list / atom / null。该函数删除原始列表的第n个元素(基于一个索引)以及它包含的任何级别子列表。该操作可以是破坏性的,也可以是非破坏性的。
所以,例如:
(remove-nth 3 '((1 2 3 4) ((1 3 5) 3 1) (1 2 2 1))) --> ((1 2 4) ((1 3) 3))
我尝试过的事情:
(defun remove-nth (n L)
(cond
((null L) nil)
((listp L)
(cons (remove-nth n (car (r n L))) (remove-nth n (cdr (r n L)))))
(t L)
)
)
(defun r (n L)
(remove (nth (- n 1) L) L)
)
此代码不起作用,因为它有时会从相同的列表中删除两次元素,例如主叫:
(remove-nth 2 '((1 2 3 4) ((1 3 5) 3 1) (1 2 2 1)))
应该输出
((1 3 4) (1 2 1))
但在我的情况下,它输出:
((1 3) (1 1))
即。子列表(1 2 2 1)删除了两个元素而不是一个。我认为我试图处理递归调用的方式存在疏忽,但我尝试了很多不同的方法,但我无法工作。所以,我已经向你们求助了。
我不是要求代码本身,而是要求解释,或暗示如何改进我的方法。
提前致谢!
答案 0 :(得分:1)
看看这段代码,它应该可以正常工作:
(defun remove-nth (n L)
(cond
((null L) nil)
((listp L)
(map 'list (lambda (l) (remove-nth n l)) (r n L)))
(t L)))
(defun r (n L)
(if (or (= n 1) (null L))
(cdr L)
(cons (car L) (r (1- n) (cdr L)))))
您的方法存在两个问题:
r
中,您没有删除第n个元素 - 您正在将每个与相等的元素移除到列表的第n个元素。因此,列表'(1 2 2 1)
已转换为'(1 1)
- 第二个元素为2
,因此每个2
都会被删除。remove-nth
中,您将向下递归到第一个元素并直接进入列表的尾部 - 由于第二个递归,您将删除更多应该使用的元素。在列表'(1 2 3 4)
的情况下,这是显而易见的。调用'(1 3 4)
后,它会变为r
,然后您将其分解为car
(等于1
)和cdr
(等于'(3 4)
)。在递归到第二个元素之后,您再次删除第二个元素,然后获得'(3)
。在cons
之后,这会为您提供列表'(1 3)
。