解决方案不是那么那么简单,您必须在迭代时跟踪找到的前一个元素,并且还要有一个标志告诉您前一个元素是否多次出现。这是我的镜头,假设输入列表不为空(如果输入列表为空,处理这种情况很简单,留给读者练习):
(define (removeReps lst)
; we need some extra parameters, use a named let for iteration
(let loop ([lst (cdr lst)] ; list to process, assuming non-empty
[prev (car lst)] ; pick first as "previous" value
[first #t]) ; flag: is this the first element in sequence?
(cond ((null? lst) ; if we reached the end of the list
(if first ; edge case: handle last element
(list prev) ; if it was the first in sequence add it
'())) ; otherwise skip it and end list
; if current element equals previous element
((equal? (car lst) prev)
; skip it, advance recursion and update flag
(loop (cdr lst) prev #f))
; new element, if previous element had exactly one repetition
(first
; add it to output, advance recursion, update prev and flag
(cons prev (loop (cdr lst) (car lst) #t)))
; new element, if previous element had more than one repetition
(else
; skip it, advance recursion, update prev and flag
(loop (cdr lst) (car lst) #t)))))
更新
我真的很喜欢 @chris 在 Haskell 中的实现:更高级别并利用现有过程而不是显式递归,它适用于空列表,并且转换为 Scheme 并不难(它在 Scheme 中比在 Haskell 中更冗长,不过。)这是使用 Racket 和 SRFI-1 的span 程序的另一个选项,请查看@chris 的答案以了解其工作原理:
(require srfi/1) ; import `span`
(define (group lst)
(match lst
['() '()]
[(cons x xs)
(let-values (((ys zs) (span (curry equal? x) xs)))
(cons (cons x ys) (group zs)))]))
(define (removeReps lst)
(filter-map (lambda (x) (and (= (length x) 1) (first x)))
(group lst)))
或者更便携,无需使用特定于 Racket 的程序和特殊形式:
(require srfi/1) ; import `span`
(define (group lst)
(if (null? lst)
'()
(let ((x (car lst))
(xs (cdr lst)))
(let-values (((ys zs) (span (lambda (e) (equal? e x)) xs)))
(cons (cons x ys)
(group zs))))))
(define (removeReps lst)
(map car
(filter (lambda (x) (= (length x) 1))
(group lst))))
让我们用一些边缘情况来测试这些过程 - 它与上述任何实现都按预期工作:
(removeReps '(a b a a a c c))
=> '(a b)
(removeReps '(x a a x b b x c c x))
=> '(x x x x)
(removeReps '(a a a))
=> '()
(removeReps '(a b b c c))
=> '(a)
(removeReps '(a a b b c c d))
=> '(d)