我正在尝试编写一个过程,该过程采用可能包含或不包含重复项的列表,然后按顺序返回该列表而不重复。到目前为止我想出的是:
(define (remove-duplicated list)
(if (null? list)
'()
(if (= (car list) (cadr list))
(cdr list)
(cons (car list) (remove-duplicates (cdr list))))))
除了对列表进行排序之外,我不太确定问题是什么。例如,如果我输入
(remove-duplicates '(3 3 4 5 6 6 7))
返回
(3 4 5 6 6 7)
答案 0 :(得分:0)
输入列表可能排序这一事实让我不知所措。我要描述的内容将用于从任何列表中删除重复元素,是否已排序。对于删除列表中重复项的一般情况,您必须使用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))))))
现在,如果输入列表排序开头,这就是修复代码的方法。我的大多数评论都适用,除了您不必使用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)
答案 1 :(得分:0)
一个相当简单的程序,它将列入可能会或可能不会的列表 包括duplicats,然后返回该列表,没有任何重复 包含,并按排序顺序。
至少有两种方法可以做到这一点:
[您的]实施失败,因为您只测试了两个 连续值,你必须搜索其余的当前元素 列表,使用成员。
如果在排序之前删除重复项,这将是一个问题,因为列表中的给定元素可能在列表中的任何其他位置具有重复项。但是,如果您首先对列表进行排序,那么可以保证任何重复的元素执行会立即跟随原始列表,因此您无需检查整个列表。如果对列表进行排序,则删除重复项会更容易,但删除重复元素后排序列表实际上并不容易,因此首先对列表进行排序并然后删除重复项确实有意义。 (我想你可能会更有效率,并编写自己的sort-and-remove-duplicates
程序,但几乎肯定不是必需的。)
如果您假设list
已经排序,则您的代码几乎正确。需要进行两项调整:
(null? list)
。但是,对于非空列表,您可以比较(car list)
和(cadr list)
,但如果list
只有一个元素,那么(cadr list)
就是错误。幸运的是,只有一个元素的列表没有重复项,因此您的基本案例可以是(or (null? list) (null? (cdr list)))
。if
的然后部分需要(remove-duplicated (cdr list))
,而不是(cdr list)
,因为list
仍可能有更多重复项(例如,(x x x ...)
或(x x y y ...)
)。这是您的代码,包含这些修改和一些注释:
(define (remove-duplicated list)
;; remove duplicates from a *sorted* list. Because the
;; list is sorted, any duplicates of an element will
;; immediately follow the first occurrence of the element.
;;---------------------------------------------------------
;; If the list has the form () or (x)
(if (or (null? list)
(null? (cdr list)))
;; then it has no duplicates, so return it
list
;; otherwise, if the list looks like (x x ...)
(if (= (car list) (cadr list))
;; then you can discard the first element, but you
;; still need to remove duplicates from the rest of
;; the list, since there can be more duplicates later
(remove-duplicated (cdr list))
;; otherwise, you need the first element of the list
;; and can simply remove-duplicated from the rest.
(cons (car list) (remove-duplicated (cdr list))))))
这可以按预期工作:
(remove-duplicated '(1 1 2 3 3 4 5 6))
;=> '(1 2 3 4 5 6)