55 lines
1.2 KiB
Racket
55 lines
1.2 KiB
Racket
#lang racket/base
|
|
|
|
;; A dset is an `equal?`-based set, but it preserves order based on
|
|
;; the history of additions, so that if items are added in a
|
|
;; deterministic order, they come back out in a deterministic order.
|
|
|
|
(provide dset
|
|
dset-empty?
|
|
dset->list
|
|
dset-add
|
|
dset-union
|
|
dset-subtract
|
|
dset-filter)
|
|
|
|
(define dset
|
|
(case-lambda
|
|
[() (hash)]
|
|
[(e) (hash e 0)]))
|
|
|
|
(define (dset-empty? ds)
|
|
(zero? (hash-count ds)))
|
|
|
|
(define (dset->list ds)
|
|
(map cdr
|
|
(sort (for/list ([(k v) (in-hash ds)])
|
|
(cons v k))
|
|
<
|
|
#:key car)))
|
|
|
|
(define (dset-add ds e)
|
|
(if (hash-ref ds e #f)
|
|
ds
|
|
(hash-set ds e (hash-count ds))))
|
|
|
|
(define (dset-union ds1 ds2)
|
|
(cond
|
|
[((hash-count ds1) . > . (hash-count ds2))
|
|
(dset-union ds2 ds1)]
|
|
[else
|
|
(for/fold ([ds2 ds2]) ([e (dset->list ds1)])
|
|
(dset-add ds2 e))]))
|
|
|
|
(define (dset-subtract ds1 ds2)
|
|
;; ! takes O(size(ds2)) time !
|
|
(for/fold ([r (dset)]) ([e (in-list (dset->list ds1))])
|
|
(if (hash-ref ds2 e #f)
|
|
r
|
|
(dset-add r e))))
|
|
|
|
(define (dset-filter ds pred)
|
|
(for/fold ([r (dset)]) ([e (in-list (dset->list ds))])
|
|
(if (pred e)
|
|
(dset-add r e)
|
|
r)))
|