Scheme: Remove duplicated numbers from list

2019-05-03 08:51发布

问题:

I wrote this code to create a list from en number of arguments given

(define (create-list . e)
   e)

But I need it to remove any duplicated numbers from the list within this block itself.

I have tried and searched for hours and can't find a solution without placing dozens of lines of code on other blocks.

For example let's say my input is

(create-list . 2 2 3 5 5 )

I need the list created to be '(2 3 5) and not '(2 2 3 5 5 )...

The order of the numbers doesn't matter.

回答1:

Basically, you need to do something like:

(define (create-list . e) (dedupe e))

I can think of a really simple but probably inefficient way to do this:

(define (dedupe e)
  (if (null? e) '()
      (cons (car e) (dedupe (filter (lambda (x) (not (equal? x (car e)))) 
                                    (cdr e))))))

If you can't use existing functions like filter, you can make one yourself:

(define (my-filter pred ls) 
  (cond ((null? ls) '())
        ((pred (car ls)) (cons (car ls) (my-filter pred (cdr ls))))
        (else (my-filter pred (cdr ls)))))


回答2:

This one is faster:

(define (remove-duplicates l)
  (cond ((null? l)
         '())
        ((member (car l) (cdr l))
         (remove-duplicates (cdr l)))
        (else
         (cons (car l) (remove-duplicates (cdr l))))))

But even better, mit-scheme provides delete-duplicates, which does exactly what you want.



回答3:

The most efficient (traversing the list once) way to do this is to define a function which goes through the list element-by-element. The function stores a list of which elements are already in the de-duped list.

An advantage of this solution over @Tikhon Jelvis's, is that the list elements don't need to be in order, to be deduplicated.

Given a function elem, which says if a is an element of l:

(define (elem? a l)
      (cond ((null? l) #f)
            ((equal? a (car l)) #t)
            (else (elem? a (cdr l)))))

We can traverse the list, storing each element we haven't seen before:

(define (de_dupe l_remaining already_contains)
   (cond ((null? l_remaining) already_contains)
         ((elem? (car l_remaining) already_contains) (de_dupe (cdr l_remaining) already_contains))
         (else (de_dupe (cdr l_remaining) (cons (car l_remaining) already_contains)))))

Note: for efficiency, this returns the elements in reverse order



回答4:

(define (delete x)
(cond
((null? x) x)
((= (length x) 1) x) | ((null? (cdr x)) x)
((= (car x) (cadr x)) (delete (cdr x)))
(#t (cons (car x) (delete (cdr x))))
)
)