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