我尝试创建一个返回列表相邻副本的函数,例如(dups'(1 2 1 1 1 4 4)应该返回列表(1 4)。
这是我到目前为止提出的代码:
(define (dups lst)
(if (equal? (car lst)(car(cdr lst)))
(cons(cdr lst) '())
(dups(cdr lst))))
此函数不会返回所有相邻的重复项,它只返回第一个相邻的重复项! 如何修复它以便返回列表的所有相邻副本?
谢谢。
答案 0 :(得分:3)
一旦您的代码找到重复内容,它就会停止处理列表的其余部分:当if
测试为真时,它会产生(cons (cdr lst) '())
。无论是否发现重复,它仍应调用dups
来处理列表的其余部分。
另外:如果您的列表没有重复项,则会遇到麻烦。
这是一个比其他人发布的更简单的解决方案:
(define (dups lst)
(if (< (length lst) 2)
; No room for duplicates
'()
; Check for duplicate at start
(if (equal? (car lst) (cadr lst))
; Starts w/ a duplicate
(if (or (null? (cddr lst)) ; end of list
(not (equal? (car lst) (caddr lst)))) ; non-matching symbol next
; End of run of duplicates; add to front of what we find next
(cons (car lst) (dups (cdr lst)))
; Othersise keep looking
(dups (cdr lst)))
; No duplicate at start; keep looking
(dups (cdr lst)))))
答案 1 :(得分:3)
基本上,这归结为仅保留与前一个元素相同但与下一个元素不同的元素。
这是使用名为let的示例实现。
(define (adj-dups lst)
(let loop ((lst (reverse (cons (gensym) lst)))
(e-2 (gensym))
(e-1 (gensym))
(acc '()))
(if (null? lst)
acc
(let ((e-0 (car lst)))
(loop (cdr lst)
e-1
e-0
(if (and (eqv? e-2 e-1) (not (eqv? e-1 e-0)))
(cons e-1 acc)
acc))))))
(gensym)
在这里派上用场,因为它是一种方便的方法,可以使用与其他所有内容不同的内容初始化工作变量,并使用需要的虚拟元素填充初始列表添加,以便我们不会错过最后一个元素。
测试:
> (adj-dups '())
'()
> (adj-dups '(1 1 4 4 1 1))
'(1 4 1)
> (adj-dups '(1 1 1 1 1))
'(1)
> (adj-dups '(1 2 1 1 1 4 4))
'(1 4)
> (adj-dups '(2 3 3 4 4 4 5))
'(3 4)
答案 2 :(得分:1)
我能想到解决这个问题的最直接的方法是使用一个内部过程,一个额外的变量来跟踪前一个元素是什么,一个布尔值来跟踪元素是否重复。然后,您可以在辅助函数和main函数之间执行相互递归,以一次构建一个重复元素的答案。
(define (dups lst)
(define (dups-helper x repeat? L)
(cond ((null? L)
(if repeat?
(list x)
'()))
((equal? x (car L))
(dups-helper x #t (cdr L)))
(else
(if repeat?
(cons x (dups L))
(dups L)))))
(if (null? lst)
'()
(dups-helper (car lst) #f (cdr lst))))
(dups (list 1 1 4 4 5 6 3 3 1))
;Value 43: (1 4 3)