OCaml函数返回最频繁

时间:2013-10-20 12:55:14

标签: list recursion ocaml frequency

假设我有一个清单:

  

[1; 3; 4; 2; 1; 5; 1]

我需要编写一个函数来返回最常出现的数字,在这种情况下输出应该是

  

int:1

有什么想法吗? 这是我到目前为止所做的,但它似乎并没有做任何事情,真的!

  

让rec r ls =与ls匹配

     

| [] - > 0

     

| hd :: tl - > if(hd ==(r tl))则1 + r tl else r tl;

5 个答案:

答案 0 :(得分:6)

您可以为每个数字构建列表中显示的次数。这可以通过列表的单次遍历来构建。

答案 1 :(得分:4)

对列表进行排序。编写一个尾递归函数,其累加器包含:

  1. 小于之前查看过的元素的最常见元素,或者最初为None
  2. 元素(1)的计数,或最初的0
  3. 之前查看的元素,最初是排序列表的头部,
  4. 元素的数量等于先前查看的元素,1最初。
  5. 调用函数传递初始累加器和排序列表的尾部。

答案 2 :(得分:2)

如果您将相同的元素与排序结合在一起并设置一个漂亮的循环不变量,这非常简单。我们的想法是扫描相同元素的运行,在每次运行结束时测试它是否是迄今为止最长的。

让它变得简单的技巧是进行预循环匹配以获得循环边缘情况(空列表)。

let most_frequent_elt list =
  let rec loop maxelt maxcount elt count = function
    | [] -> if count > maxcount then elt else maxelt
    | x::xs ->
        if elt = x then loop maxelt maxcount elt (count + 1) xs
        else if count > maxcount then loop elt count x 1 xs
        else loop maxelt maxcount x 1 xs in
  match List.sort compare list with
   | [] -> None
   | x::xs -> Some (loop x 0 x 1 xs)

答案 3 :(得分:0)

基本上实施lukstafi的答案(使用可变字段):

type 'a accumulator = { mutable curr: 'a option; mutable cnt: int; 
  mutable el: 'a option; mutable max: int; }

let rec process acc = function
  | [] -> acc.el
  | hd::tl -> 
    if Some(hd) = acc.curr then begin
      acc.cnt <- (acc.cnt + 1);
      if acc.cnt > acc.max then
        acc.max <- acc.cnt;
        acc.el <- Some(hd)
    end
    else begin
      acc.cnt <- 1;
      acc.curr <- Some hd
    end;
    process acc tl

let option2string = function | None -> "" | Some v -> string_of_int v

let () = 
  let sorted = List.sort compare [1;3;4;2;1;5;1] in
  let init = { curr = None; cnt = 0; el = None; max = 0 } in
  print_endline (option2string (process init sorted))

答案 4 :(得分:0)

最新答案,但根据count unique elements in list in OCaml的基准,使用Hashtbl可以取得良好的性能。

然后,对元素及其出现次数进行简单排序,即可获得列表中最常见的元素。

module IntHash =
  struct
    type t = int
        let equal i j = i=j
        let hash i = i land max_int
  end

module IntHashtbl = Hashtbl.Make(IntHash)


let count_unique_elements_int_hashtbl list =
  let counter = IntHashtbl.create 10000 in
  let update_counter x =
    if IntHashtbl.mem counter x then
      let current_count = IntHashtbl.find counter x in
      IntHashtbl.replace counter x (succ current_count)
    else
      IntHashtbl.replace counter x 1
  in
  List.iter update_counter list;
  IntHashtbl.to_seq counter
  |> List.of_seq


let most_common_element_in_int_list list =
  count_unique_elements_int_hashtbl list
  |> List.sort (fun x y -> compare (snd x) (snd y)) 
  |> List.rev
  |> List.hd
  |> fst 

let () =
  assert (most_common_element_in_int_list [1;2;1] = 1);
  assert (most_common_element_in_int_list [6;1;2;1;6;6] = 6);