给出一个清单,
(define ll '(a a a b c c c d e e e e))
我想删除所有非重复元素,只留下副本的一个副本,即删除后,结果将是
(a c e)
我的算法是:
遍历列表,将当前元素与下一个元素进行比较。
如果它们相等,那么cons
当前元素与下一个递归调用的列表。例如,
(a a a b c)
从左向右移动,遇到a
和a
。
(cons a (remove-nondup (cddr lst)))
否则,跳过当前和下一个元素。
(remove-nondup (cddr lst))
我遇到的问题是
(define (remove-nondup lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-nondup (cdr lst)))
(remove-nondup (cddr lst)))
lst))
我遇到的问题是如果有超过3个连续元素,我无法跟踪前一个元素。所以我想我应该使用另一个程序来删除所有重复项?或者我可以把它们放到一个程序中?
所以我当前的替代解决方案是,
(define (remove-dup lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-dup (cddr lst)))
(cons (car lst) (remove-dup (cdr lst))))
lst))
(define (remove-nondup-helper lst)
(if (>= (length lst) 2)
(if (eq? (car lst) (cadr lst))
(cons (car lst) (remove-nondup-helper (cdr lst)))
(remove-nondup (cddr lst)))
lst))
; call the helper function and remove-dup
(define (remove-nondup lst)
(remove-dup (remove-nondup-helper lst)))
答案 0 :(得分:1)
这是我的解决方案:首先,抓住bagify
(任何版本都可以)。然后:
(define (remove-singletons lst)
(define (singleton? ass)
(< (cdr ass) 2))
(map car (remove singleton? (bagify lst))))
remove
来自SRFI 1.如果您使用的是Racket,请先运行(require srfi/1)
。或者,使用这个简单的定义:
(define remove #f) ; Only needed in Racket's REPL
(define (remove pred lst)
(cond ((null? lst) lst)
((pred (car lst)) (remove pred (cdr lst)))
(else (cons (car lst) (remove pred (cdr lst))))))
答案 1 :(得分:0)
这是一种仅使用标准库函数和尾部调用的方法,但它执行线性搜索以查看项目是否已被查看或放入结果中:
(define remove-nondup
(λ (ls)
(reverse
(let loop ([ls ls] [found '()] [acc '()])
(cond
[(null? ls)
acc]
[(memq (car ls) found)
(loop (cdr ls)
found
(if (memq (car ls) acc)
acc
(cons (car ls) acc)))]
[else
(loop (cdr ls)
(cons (car ls) found)
acc)])))))
(remove-nondup '(a a a b c c c d e e e e)) =>
(a c e)
(remove-nondup '(a a a b c c c d e e e e f a a f)) =>
(a c e f)
loop
是一个“命名为let”:一种在程序中粘贴辅助程序而不会产生大量语法混乱的方便方法。
如果您只想将连续重复项缩小到一个项目,并且仅在连续两次没有出现项目时删除项目,那么这里有一种方法可以在两个单元格之前“记住”该项目搜索它,并仅使用尾调用:
(define remove-nonconsecdup
(λ (ls)
(reverse
(letrec (
[got1 (λ (ls prev acc)
(cond
[(null? ls)
acc]
[(eq? prev (car ls))
(got2 (cdr ls) (cons prev acc))]
[else
(got1 (cdr ls) (car ls) acc)]))]
[got2 (λ (ls acc)
(cond
[(null? ls)
acc]
[(eq? (car acc) (car ls))
(got2 (cdr ls) acc)]
[else
(got1 (cdr ls) (car ls) acc)]))])
(if (null? ls)
'()
(got1 (cdr ls) (car ls) '()))))))
(remove-nonconsecdup '(a a a b c c c d e e e e)) =>
(a c e)
(remove-nonconsecdup '(a a a b c c c d e e e e f a a f)) =>
(a c e a)
我不喜欢倒转列表,但调用reverse
很容易。如果由reverse
完成的额外收费是一个问题,你可以进行非尾调用或将项目粘贴在列表的末尾,但这样做更难有效(但使用非标准库很容易)宏)。