输入列表可能已排序这一事实让我不以为然。我将要描述的内容将适用于从任何列表中删除重复元素,无论是否排序。对于删除列表中重复项的一般情况,您必须使用 member 搜索列表其余部分中的当前元素。
此外,在这两种情况下,您都必须推进递归,并注意在最后一行中您调用的是remove-duplicates(这是某些解释器的内置过程,所以也许您不必从头开始实现它!),但是您将过程命名为remove-duplicated。附带说明一下,将参数命名为 list 是个坏主意,这会与内置函数发生冲突——我冒昧地重命名了它。这将解决问题,这是一个更通用的解决方案:
; if the input list is not sorted, use this
(define (remove-duplicated lst)
(if (null? lst)
'()
(if (member (car lst) (cdr lst)) ; changes here
(remove-duplicated (cdr lst)) ; and here
(cons (car lst)
(remove-duplicated (cdr lst))))))
现在,如果输入列表开始时排序,这就是修复代码的方法。我的大多数 cmets 都适用,除了您不必使用 member 并且基本情况略有不同:
; if the input list is sorted, use this
(define (remove-duplicated lst)
(if (or (null? lst) (null? (cdr lst))) ; changes here
lst
(if (= (car lst) (cadr lst))
(remove-duplicated (cdr lst)) ; and here
(cons (car lst)
(remove-duplicated (cdr lst))))))
无论哪种方式,只要您对输入使用正确的输入,该过程就会按预期工作(第一个实现适用于已排序的 或 未排序的输入列表,第二个实现仅适用于已排序的列表):
(remove-duplicated '(3 3 4 5 6 6 7)) ; sorted input, both implementations work
=> '(3 4 5 6 7)
最后,如果您需要确保输出列表将始终排序,但不能保证输入列表已排序,则使用我的第一个实现 remove-duplicated 并在之后对其进行排序,检查您的解释器以找到找出哪些排序程序可用 - 以下将在 Racket 中起作用:
(sort (remove-duplicated '(3 6 3 7 4 5 6)) <) ; using my first remove-duplicated
=> '(3 4 5 6 7)
... 或者先对列表进行排序,然后使用我的第二个实现 remove-duplicated。你有很多选择来解决这个问题!
(remove-duplicated (sort '(3 6 3 7 4 5 6) <)) ; using my second remove-duplicated
=> '(3 4 5 6 7)