[racket] multi[set,hash] question

From: Greg Hendershott (greghendershott at gmail.com)
Date: Wed Jan 8 12:54:57 EST 2014

> Is there support in racket for hash tables where there could be a few (> 1)
> entries with the same key?
>
> Like std::multiset in C++

I'm not familiar with std:multiset and all it might do.

It's not hard in Racket to store a `list` of things as the value in a
hash table. Actually a `set` would be a better choice. So in
contract-ish notation:

    (hash/c any/c (set/c any/c))

Then write a few small wrapper functions to do the equivalent of
`hash-set` and `hash-remove`, but taking into account the fact that
the hash values are `set`s.

Here's my quick attempt at such wrappers for both mutable and immutable:

    #lang racket

    ;; Helpers for (hash/c any/c (set/c any/c))

    (define (hash-set/multi h k v)
      (hash-set h k (set-add (hash-ref h k (set)) v)))

    (define (hash-remove/multi h k v)
      (define s (set-remove (hash-ref h k) v))
      (cond [(set-empty? s) (hash-remove h k)]
            [else (hash-set h k s)]))

    (define (hash-set/multi! h k v)
      (hash-set! h k (set-add (hash-ref h k (set)) v)))

    (define (hash-remove/multi! h k v)
      (define s (set-remove (hash-ref h k) v))
      (cond [(set-empty? s) (hash-remove! h k)]
            [else (hash-set! h k s)]))


    ;; Usage
    (displayln "mutable example:")
    (define h (make-hash))
    h
    (hash-set/multi! h 'key "a")
    h
    (hash-set/multi! h 'key "b")
    h
    (hash-remove/multi! h 'key "a")
    h
    (hash-remove/multi! h 'key "b")
    h

    (displayln "immutable example:")
    (for/fold ([h (for/fold ([h (hash)])
                            ([v '("a" "b")])
                    (print h) (newline)
                    (hash-set/multi h 'key v))])
              ([v '("a" "b")])
      (print h) (newline)
      (hash-remove/multi h 'key v))

Posted on the users mailing list.