dset.rkt (1250B)
1 #lang racket/base 2 3 ;; A dset is an `equal?`-based set, but it preserves order based on 4 ;; the history of additions, so that if items are added in a 5 ;; deterministic order, they come back out in a deterministic order. 6 7 (provide dset 8 dset-empty? 9 dset->list 10 dset-add 11 dset-union 12 dset-subtract 13 dset-filter) 14 15 (define dset 16 (case-lambda 17 [() (hash)] 18 [(e) (hash e 0)])) 19 20 (define (dset-empty? ds) 21 (zero? (hash-count ds))) 22 23 (define (dset->list ds) 24 (map cdr 25 (sort (for/list ([(k v) (in-hash ds)]) 26 (cons v k)) 27 < 28 #:key car))) 29 30 (define (dset-add ds e) 31 (if (hash-ref ds e #f) 32 ds 33 (hash-set ds e (hash-count ds)))) 34 35 (define (dset-union ds1 ds2) 36 (cond 37 [((hash-count ds1) . > . (hash-count ds2)) 38 (dset-union ds2 ds1)] 39 [else 40 (for/fold ([ds2 ds2]) ([e (dset->list ds1)]) 41 (dset-add ds2 e))])) 42 43 (define (dset-subtract ds1 ds2) 44 ;; ! takes O(size(ds2)) time ! 45 (for/fold ([r (dset)]) ([e (in-list (dset->list ds1))]) 46 (if (hash-ref ds2 e #f) 47 r 48 (dset-add r e)))) 49 50 (define (dset-filter ds pred) 51 (for/fold ([r (dset)]) ([e (in-list (dset->list ds))]) 52 (if (pred e) 53 (dset-add r e) 54 r)))