backport-template-pr1514/experimental/dset.rkt
Georges Dupéron e463102f09 Initial commit
2016-11-10 17:32:48 +01:00

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)))