(chapter-start ‘hash-manipulation “utilities for manipulating, accessing and altering hash objects”)

; return values for each key in hash ‘h (def hash-values (h)

(map λk(hash-get h k)
     (hash-keys h)))

; (auto-hash a b c) same as { a a b b c c } (mac auto-hash names

`(brace-list ,@(flatten:map λn(list n n) names)))

;; allows #(a b c) as shortcut for (auto-hash a b c) ;; which is itself a shortcut for { a a b b c c } (define-prefix-list-macro “#” no-vars keys

`(auto-hash ,@keys))

;; like ‘map, but for a hash instead of a list ; provided function ’f takes three arguments, ;; a key, the corresponding value from the given hash, and the index of the item in the list (def map-hash (f h pre)

(map-with-index λki(f k (hash-get h k) i)
                ((or pre x1) (hash-keys h))))

;; returns a new hash with the same keys as the given hash, with each value transformed by ;; the given function ‘f ;; ’f takes three arguments: ;; k, the key ;; v, the value ;; i, the index ;; (def hash-transform-values (f h)

(returnlet newh {}
  (map-hash λkvi(hash-set newh k (f k v i)) h)))

;; Return a new hash where keys are (map f things) and corresponding values are (map g things). ;; No attempt is made to avoid clobbering items. Use ‘group-by instead, if there are duplicate keys. ;; ;; example: (hashify &firstname x1 people) returns { “johann” <bach record> “ludwig” <beethoven record> } ;; ;; reverse: (hashify x1 &firstname people) returns { <bach record> “johann” <beethoven record> “ludwig” } ;; ;; example: (hashify &firstname &lastname people) returns { “johann” “bach” “ludwig” “van beethoven” } ;; ;; example: (hashify &born &lastname people) returns { 1685 “bach” 1770 “van beethoven” } ;; ;; reverse example: (hashify &lastname &born people) returns { “bach” 1685 “van beethoven” 1770 } (def hashify (f g things)

(returnlet hsh {}
           (each thing things
                 (hash-set hsh (f thing) (g thing)))))

;; like ‘group-by, except ’f returns multiple items, each of which ;; is used to key the thing in question (def subgroup-by (f things)

(returnlet hsh {}
  (each thing things
        (each k (f thing)
              (hash-cons hsh k thing)))))

;; return a new hash containing all the values of the given ;; hash, but with each corresponding key ‘k replaced by (f k) (def hash-replace-keys (f hsh)

(returnlet newh {}
  (each k (hash-keys hsh)
    (hash-set newh (f k) (hash-get hsh k)))))

;; repeatedly assigns an element of hash-keys of ‘things to ’kvar, ;; assign the corresponding value to ‘vvar ;; and executes ’body for each key-value pair ;; return value of form is whatever the last line of ‘body returns (mac hash-each (kvar vvar things . body)

(w/uniq xs
  `(let ,xs ,things
     (each ,kvar (hash-keys ,xs)
       (let ,vvar (hash-get ,xs ,kvar)
         ,@body)))))

;; merge two hashes of the format k => (v0 v1…) ;; ;; example: h0 is { a (1 2) b (3 4) }, h1 is { a (2 5) c (6 7) } ;; ;; (hash/merge-lists h0 h1) will be: { a (1 2 5) b (3 4) c (6 7) } ;; ;; Uses set-union when merging lists, so merged lists ;; contain no duplicates. (def hash/merge-lists (h0 h1)

(returnlet h (hash-merge { } h0)
  (each k (hash-keys h1)
    (= h.,k (⋃ h.,k h1.,k)))))