如何找到列表中出现次数最多的元素?
如果有更多相同的号码,则可以返回任何号码。
例如,对于列表'(1 3 3 4 2 2)
,该函数可以返回2
或3
。
我想我可以计算每个元素的出现次数,然后选择最大值,但这看起来效率低下。有没有更好的方法,甚至更好的内置功能?
答案 0 :(得分:2)
这是一个基于Racket哈希表的解决方案。
#lang racket
(define (most-frequent-element xs)
(define ht (make-hash))
(for ([x xs]) (hash-update! ht x add1 0))
(for/fold ([max-x #f] [max-count 0]) ([(x c) ht])
(if (> c max-count)
(values x c)
(values max-x max-count))))
示例:
> (most-frequent-element '(a b c c d a a b c a))
'a
4
以下是argmax
的解决方案。不幸的是它需要
从哈希表到列表的转换。
#lang racket
(define (most-frequent-element xs)
(define ht (make-hash))
(for ([x xs]) (hash-update! ht x add1 0))
(argmax (λ (x) (hash-ref ht x 0))
(hash->list ht)))
示例:
> (most-frequent-element '(a b c c d a a b c a))
'(a . 4)
答案 1 :(得分:1)
O(n)
版本
#!r6rs
(import (rnrs base)
(srfi :69))
(define (max-occurence lst)
(define hash (make-hash-table))
(define zero (lambda () 0))
(let loop ((lst lst) (mfreq 0) (mcur #f))
(if (null? lst)
mcur
(let* ((element (car lst)) (freq (+ 1 (hash-table-ref hash element zero))))
(hash-table-set! hash element freq)
(if (> freq mfreq)
(loop (cdr lst) freq element)
(loop (cdr lst) mfreq mcur))))))
#!racket
版本的版本非常相似,只是惯用版本会选择不可变的哈希表。
#!racket
(define (max-occurence lst)
(let loop ((hash (make-immutable-hash)) (lst lst) (mfreq 0) (mcur #f))
(if (null? lst)
mcur
(let* ((element (car lst)) (freq (add1 (hash-ref hash element 0))))
(if (> freq mfreq)
(loop (hash-set hash element freq)
(cdr lst)
freq
element)
(loop (hash-set hash element freq)
(cdr lst)
mfreq
mcur))))))
如果您遇到列表性能问题,我猜您会看到其中任何一个都有很大改进。在#!racket
中更改为可变哈希表会使速度加倍,但我怀疑你需要它。
答案 2 :(得分:0)
如果在计算之前对列表进行排序,则可以稍微提高效率。然后具有特定值的所有元素将在列表中一起。然后,当您完成对示例列表中2的计数时,您不必再保留1的数字,因为您的函数已经知道1不是具有最多出现次数的元素。