[racket] ranking items by their appearance in sets
Hi all,
Given a list of sets of symbols, I want to rank the symbols based on how
many sets they appear in. I prefer to be completely functional.
Below are 2 different implementations I came up with, with tests. I'm
looking for criticism in any aspect, but most importantly I'm wondering
whether there is a simpler implementation.
Thanks.
David
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
#lang racket
(require rackunit)
(define (rank-set-elements/1 list-of-sets)
(define list-of-lists (map set->list list-of-sets))
(define flat-list (flatten list-of-lists))
(define sorted-flat-list (sort flat-list symbol<?))
(define list-of-item-frequency-pairs
(foldl (lambda (v accum)
(match accum
[(list-rest (cons sym cnt) rst)
(if (eq? sym v)
(cons (cons sym (add1 cnt)) rst)
(cons (cons v 1) accum))]
[else
(list (cons v 1))]))
'()
sorted-flat-list))
(sort list-of-item-frequency-pairs > #:key cdr))
(define (rank-set-elements/2 list-of-sets)
(define hash-of-item-frequencies
(for*/fold ([frequencies (hash)])
([a-set list-of-sets]
[sym a-set])
(hash-update frequencies sym add1 0)))
(define list-of-item-frequency-pairs (hash->list hash-of-item-frequencies))
(sort list-of-item-frequency-pairs > #:key cdr))
(define input
(shuffle
(map list->set
'((a)
(a b)
(a b c)
(a b c d)
(a b c d e)))))
(define expected
'((a . 5)
(b . 4)
(c . 3)
(d . 2)
(e . 1)))
(check-equal? (rank-set-elements/1 '()) '())
(check-equal? (rank-set-elements/1 input)
expected)
(check-equal? (rank-set-elements/2 '()) '())
(check-equal? (rank-set-elements/2 input)
expected)