我正在尝试在Scheme中编写一个函数make-set
,它接受一个列表,可能包含列表,并删除所有重复项。例如,(make-set '(1 (2 3) (2 3)))
应返回(1 (2 3))
,而(make-set '(1 (2 2) 3))
应返回(1 (2) 3)
。到目前为止,这是我的代码:
(define make-set
(lambda (lst)
(cond ((empty? lst) lst)
((not (list? lst)) (list lst))
((member? (car lst) (cdr lst))
(cons (car lst)
(make-set (delete (car lst) (cdr lst)))))
((list? (car lst))
(cons (make-set (car lst))
(make-set (cdr lst))))
((equal? (set-len lst) 1)
lst)
(else (cons (car lst) (make-set (cdr lst)))))))
适用于我提到过的案例。但是,如果我例如写(make-set '((1 1) (1 1 1)))
我得到答案((1) (1))
,那么它会创建新的重复项。不知怎的,我想说,如果还有重复,它应该再次运行该功能,但我不知道如何。
(我在make-set
中使用的其他函数是member?
,它检查一个元素(可以是一个列表)是否在另一个列表中,delete
删除所有出现的列表中的元素(可以是列表)和返回列表长度的set-len
。)
答案 0 :(得分:0)
您还没有真正指定在列表的不同级别应该发生什么,例如,如果您从(2 (2 3))
开始,但对于您指定的情况,以下情况有效。我们的想法是,您要在每个级别展平元素,然后然后删除重复元素。尽管如此,调用这个make-set
有点用词不当,因为它并不是一个你试图回归的集合。否则,((1 1) (1 1 1))
可能会返回((1 1) (1 1 1))
,因为(1 1)
与(1 1 1)
不同。也就是说,此代码适用于您展示的示例。
(define (remove-duplicates list)
(if (null? list)
list
(let ((tail (remove-duplicates (cdr list))))
(if (member (car list) tail)
tail
(cons (car list) tail)))))
(define (make-set tree)
(if (not (pair? tree))
tree
(remove-duplicates (map make-set tree))))
(make-set '((1 1) (1 1 1)))
;=> ((1))
(make-set '(1 (2 3) (2 3)))
;=> (1 (2 3))
答案 1 :(得分:0)
我同意约书亚的意见,我应该修改算法以避免陷入这种情况。但我会首先回答你提出的问题:不知怎的,我想说如果还有重复,它应该再次运行该功能,但我不知道如何。
实际上这很简单:只需循环直到结果与您传递的列表相同:
(define make-full-set
(lambda (lst)
(let ((r (make-set lst)))
(if (equal? r lst)
r
(make-full-set r)))))
测试:
> (make-full-set '((1 1) (1 1 1)))
'((1))
当然这是笨拙和低效的(需要一个额外的通行证和昂贵的列表比较)所以我们真的需要一个更好的算法。根据我的解释,这是我的看法,即所有 atoms 应该是唯一的:
(define (make-set lst)
(define (sub lst items res)
(if (null? lst)
(values items (reverse res))
(let ((c (car lst)))
(cond
((list? c) (let-values (((items2 res2) (sub c items '())))
(sub (cdr lst) items2 (if (null? res2) res (cons res2 res)))))
((member c items) (sub (cdr lst) items res))
(else (sub (cdr lst) (cons c items) (cons c res)))))))
(let-values (((_ res) (sub lst '() '()))) res))
测试:
> (make-set '((1 1) (1 1 1)))
'((1))
> (make-set '(2 (2 3)))
'(2 (3))
> (make-set '(2 (2 3)))
'(2 (3))