List order after duplicate filtering

2020-04-16 02:27发布

I'm trying to teach myself functional language thinking and have written a procedure that takes a list and returns a list with duplicates filtered out. This works, but the output list is sorted in the order in which the last instance of each duplicate item is found in the input list.

(define (inlist L n)
  (cond
   ((null? L) #f)
   ((= (car L) n) #t)
   (else (inlist (cdr L) n))
   ))

(define (uniquelist L)
 (cond
   ((null? L) '())
   ((= 1 (length L)) L)
   ((inlist (cdr L) (car L)) (uniquelist (cdr L)))
   (else (cons (car L) (uniquelist (cdr L))))
   ))

So..

(uniquelist '(1 1 2 3)) => (1 2 3)

...but...

(uniquelist '(1 2 3 1)) => (2 3 1)

Is there a simple alternative that maintains the order of the first instance of each duplicate?

标签: scheme racket
1条回答
聊天终结者
2楼-- · 2020-04-16 02:54

The best way to solve this problem would be to use Racket's built-in remove-duplicates procedure. But of course, you want to implement the solution from scratch. Here's a way using idiomatic Racket, and notice that we can use member (another built-in function) in place of inlist:

(define (uniquelist L)
  (let loop ([lst (reverse L)] [acc empty])
    (cond [(empty? lst)
           acc]
          [(member (first lst) (rest lst))
           (loop (rest lst) acc)]
          [else
           (loop (rest lst) (cons (first lst) acc))])))

Or we can write the same procedure using standard Scheme, as shown in SICP:

(define (uniquelist L)
  (let loop ((lst (reverse L)) (acc '()))
    (cond ((null? lst)
           acc)
          ((member (car lst) (cdr lst))
           (loop (cdr lst) acc))
          (else
           (loop (cdr lst) (cons (car lst) acc))))))

The above makes use of a named let for iteration, and shows how to write a tail-recursive implementation. It works as expected:

(uniquelist '(1 1 2 3))
=> '(1 2 3)

(uniquelist '(1 2 3 1))
=> '(1 2 3)
查看更多
登录 后发表回答