utils: Add hash-filter.

This commit is contained in:
Sergiu Ivanov 2020-10-31 00:19:38 +01:00
parent 208dc12060
commit 73756d8974

View file

@ -55,7 +55,11 @@
[#:combine (-> any/c any/c any/c)
#:combine/key (-> any/c any/c any/c any/c)]
#:rest (listof hash?)
(and/c hash? immutable?))])
(and/c hash? immutable?))]
[hash-filter (->* (hash?)
(#:predicate (-> any/c boolean?)
#:predicate/key (-> any/c any/c boolean?))
hash?)])
;; Contracts
(contract-out [variable-mapping? contract?]
[string-variable-mapping? contract?]
@ -624,6 +628,35 @@
(check-equal? (hash-intersect h1 h3 #:combine -)
'#hash((a . -6) (c . -5)))))
;;; Functionally filters a hash table: only keeps the key-value pairs
;;; that satisfy a given criterion.
;;;
;;; The filtering criterion should be specified either via #:predicate
;;; or #:predicate/key. #:predicate should be a function returning
;;; a Boolean result given a value of the hash value. #:predicate
;;; should be a function taking a key and the corresponding value.
(define (hash-filter
ht
#:predicate [predicate #f]
#:predicate/key [predicate/key
(if predicate
(λ (_ v) (predicate v))
(error 'hash-filter))])
(for/fold ([filtered-pairs (hash-clear ht)])
([(k v) (in-hash ht)])
(if (predicate/key k v)
(hash-set filtered-pairs k v)
filtered-pairs)))
(module+ test
(test-case "hash-filter"
(check-equal? (hash-filter (hash 'a 0 'b 1 'c 0)
#:predicate (compose not zero?))
#hash((b . 1)))
(check-equal? (hash-filter (hash 'a 0 'b 1 'c 0) #:predicate/key
(λ (k v) (and (eq? k 'b) (not (zero? v)))))
'#hash((b . 1)))))
;;; =========
;;; Functions
;;; =========