(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" "ludwig" } ;; ;; reverse: (hashify x1 &firstname people) returns { "johann" "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)))))