如何从Scheme中的列表中删除非重复元素?
给定一个列表,
(define ll '(a a a b c c c d e e e e))
我想删除所有非重复元素并只留下重复元素的一个副本,即删除后,结果将是
(a c e)
我的算法是:
遍历列表,将当前元素与下一个元素进行比较。
如果它们相等,则
<前><代码>(aaabc)cons
当前元素与下一个递归调用的列表。例如,从左向右移动,遇到
a
和a
。(cons a (remove-nondup (cddr lst)))
否则,跳过当前和下一个元素。
(删除-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)))
Given a list,
(define ll '(a a a b c c c d e e e e))
I want to remove all non-duplicate elements and leave only one copy of the duplicate one, i.e. after removing, the result would be
(a c e)
My algorithm is:
Traverse through the list, comparing current element with next element.
If they're equal, then
cons
the current element with the list of the next recursive call. For example,(a a a b c)
Move from left to right, encounter
a
anda
.(cons a (remove-nondup (cddr lst)))
Otherwise, skip current and next element.
(remove-nondup (cddr lst))
The problem I'm having is
(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))
The problem that I'm having is if there are more than 3 consecutive elements, I have no way to keep track of the previous-previous one. So I wonder should I use another procedure to remove all duplicates? or I can just put them into one procedure?
So my alternative current solution was,
(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)))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是我的解决方案:首先,抓住
bagify
(任何版本都可以)。然后:remove
来自 SRFI 1。如果您使用 Racket,请先运行(require srfi/1)
。或者,使用这个简单的定义:Here's my solution: first, grab
bagify
(any version will do). Then:remove
is from SRFI 1. If you're using Racket, run(require srfi/1)
first. Or, use this simple definition:这是一种仅使用标准库函数和尾部调用的方法,尽管它执行线性搜索以查看某个项目是否已被看到或放入结果中:
循环
是一个“命名的let”:一种将辅助过程粘贴到过程中的便捷方法,而不会出现大量语法混乱。如果您只想将连续重复项缩小为一个项目,并且仅在它们不连续出现两次时删除项目,那么这里有一种方法可以“记住”两个单元格前的项目,而无需搜索它,并且仅使用尾部调用:
我不喜欢反转列表,但调用
reverse
很容易。如果由reverse
完成的额外 cons'ing 是一个问题,您可以进行非尾部调用或将项目粘贴在列表的末尾,但这很难有效地完成(但使用非尾部调用很容易) -标准库宏)。Here's a way that uses only standard library functions and only tail calls, though it performs linear searches to see if an item has already been seen or put in the result:
The
loop
is a "named let": a handy way to stick a helper procedure inside a procedure without a lot of syntactic clutter.If you only want to shrink consecutive duplicates down to one item, and remove items only when they don't occur twice consecutively, then here's a way to "remember" the item two cells ago without searching for it, and using only tail calls:
I don't like reversing lists, but calling
reverse
is easy. If the extra cons'ing done byreverse
is a problem, you could do non-tail calls or stick the items at the end of the list, but that's harder to do efficiently (but easy with a non-standard library macro).