This is definitely a useful thing to have and I've wanted it myself before. However I'm generally of the opinion that we should avoid making more collection manipulation functions that are unnecessarily specialized to one type of collection. I'd like to see functions that operate on all sequences rather than on hash tables alone. Here are some usages of hash-filter compared with some existing alternatives:
(hash-filter ht #:predicate pred) == ; Sequence composition (make-immutable-hash (sequence->list (sequence-filter (lambda (pair) (pred (cdr pair))) (sequence-map cons ht)))) == ; For macros (for/hash ([(k v) (in-hash ht)] #:when (pred v)) (values k v)) The for macro is probably what I'd reach for in standard racket code. It has some drawbacks: the first time I tried to write it I forgot to write (values k v) and instead just wrote v. Keeping track of pulling apart the key and value, naming them with variables, and putting them back together is a little annoying. The sequence composition approach is, in my humble opinion, completely unreadable and difficult to write to boot. The sequence-map function works totally fine on multivalued sequences but sequence-filter only works on single-value sequences, so we have to do a dance with cons car and cdr to turn the multivalued sequence of keys and values into a single-valued sequence of key-value cons pairs. Furthermore, the only built-in function for building a hash table from a sequence is overly specialized to lists, so you have to copy the sequence into a list solely so you can turn that list into a hash table with make-immutable-hash. Instead of adding hash-filter to racket/hash, I think there's a few improvements we could make to the sequence composition side of things: - Make sequence-filter allow multivalued sequences, provided the arity of the predicate is consistent with the arity of the sequence. - Add a sequence->hash function that accepts a multivalued sequence of keys and values (exactly like what in-hash produces) and copies them into a hash table. For the filter-by-value, filter-by-key, and filter-by-key-and-value cases, this lets us write: (sequence->hash (sequence-filter (lambda (k v) (pred v)) ht)) ; Filter values (sequence->hash (sequence-filter (lambda (k v) (pred k)) ht)) ; Filter keys (sequence->hash (sequence-filter pred ht)) ; Filter key-value pairs Which is close enough to hash-filter to satisfy my desire for conciseness, while still being general enough to work with other kinds of key-value sequences. Shameless self plug: you might be interested in Rebellion <https://docs.racket-lang.org/rebellion/index.html>'s take on this, which uses transducers <goog_836594457> and key-value structs called entries <https://docs.racket-lang.org/rebellion/Entries.html>: (transduce (in-hash-entries ht) (filtering-values pred) #:into into-hash) ; Filter values (transduce (in-hash-entries ht) (filtering-keys pred) #:into into-hash) ; Filter keys (transduce (in-hash-entries ht) (filtering (lambda (e) (pred (entry-key e) (entry-value e)))) #:into into-hash) ; Filter key-value entries On Friday, October 30, 2020 at 4:35:31 PM UTC-7 unlimitedscolobb wrote: > Hi, > > I am currently using hash tables a lot, so inevitably I end up writing > general functions. I wrote the following `hash-filter`: > > ``` > (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))) > ``` > > Before I submit a pull request to the Racket repository, I would like to > know whether adding this function to `racket/hash` is a good idea, or > whether I should create a separate package with extra functions for hash > tables. > > - > Sergiu > -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to racket-users+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/98498f48-9d02-4f4e-91fd-ab85bf6d765an%40googlegroups.com.