首先,您需要确定键值数据类型。您可以使用关联列表,但哈希表是更有效的选择。
让我们从一个简短的列表开始:
(define-struct movie (title genre stars))
(define films
(list
(make-movie "Godfater" "Crime" '("Marlon Brando" "Al Pacino"))
(make-movie "Rambo" "Thriller" '("Sylvester Stallone"))
(make-movie "Silence of the Lambs" "Crime" '("Jodie Foster" "Anthony Hopkins"))))
并创建一个空哈希表
(define h (make-hash))
现在我们处理每一部电影,同时更新哈希表:
> (for-each (lambda (e) (hash-update! h e add1 0)) (map movie-genre films))
> h
'#hash(("Thriller" . 1) ("Crime" . 2))
现在我们需要找到最高计数:
> (hash-values h)
'(1 2)
> (define most (foldl (lambda (e r) (if (> e r) e r)) 0 (hash-values h)))
> most
2
所以 2 是我们的最高计数。现在我们创建一个计数为 2 的所有类型的列表:
> (hash->list h)
'(("Thriller" . 1) ("Crime" . 2))
> (foldl
(lambda (e r) (if (= (cdr e) most) (cons (car e) r) r))
null
(hash->list h))
'("Crime")
把它们放在一起:
(define (count-by-genre lst)
(define h (make-hash))
(for-each (lambda (e) (hash-update! h e add1 0)) (map movie-genre lst))
(define most (foldl (lambda (e r) (if (> e r) e r)) 0 (hash-values h)))
(foldl
(lambda (e r) (if (= (cdr e) most) (cons (car e) r) r))
null
(hash->list h)))
但这是非常低效的,原因如下:
- 更新哈希表后,我们必须重新迭代它,创建一个列表,然后应用
foldl
以找到最高值,而我们本可以在更新哈希表时记下它
- 然后我们再次创建一个完整列表 (
hash->list
) 和一个最终结果列表,使用foldl
.
很多consing和东西。使用特定于 Racket 的结构的另一种更有效的版本for
可能是:
(define (count-by-genre lst)
(define h (make-hash))
(define most
(for/fold ((highest 0)) ((e (in-list (map movie-genre lst))))
(define new (add1 (hash-ref h e 0)))
(hash-set! h e new)
(max highest new)))
(for/fold ((res null)) (((k v) (in-hash h)))
(if (= v most) (cons k res) res)))