[racket] ranking items by their appearance in sets

From: David T. Pierson (dtp at mindstory.com)
Date: Wed Sep 24 00:29:09 EDT 2014

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.



#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))]
                      (list (cons v 1))]))
  (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
         (map list->set
                (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)

(check-equal? (rank-set-elements/2 '()) '())
(check-equal? (rank-set-elements/2 input)

Posted on the users mailing list.