在Racket的列表中查找出现次数最多的元素

时间:2015-03-22 11:41:02

标签: scheme racket

如何找到列表中出现次数最多的元素?

如果有更多相同的号码,则可以返回任何号码。

例如,对于列表'(1 3 3 4 2 2),该函数可以返回23

我想我可以计算每个元素的出现次数,然后选择最大值,但这看起来效率低下。有没有更好的方法,甚至更好的内置功能?

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)

使用SRFI-69 hash tables

的R6RS计划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不是具有最多出​​现次数的元素。