Home > Enterprise >  SML, How to find number of occurrences of the minimum number in a list?
SML, How to find number of occurrences of the minimum number in a list?

Time:11-18

In SML is it possible to find the number of occurrences of the min number in a list?

I have code to find the number of occurrences of a number but i am stumped on how to find the min and use it to find how many of the minimum num there is.

fun occurrences(nil, n)=0
|   occurrences(ls, n) =
    if hd(ls)=n then occurrences(tl(ls),n)   1
    else occurrences(tl(ls),n)   0;

Thank you!

CodePudding user response:

You can write a function that keeps track of the min value and its count as you iterate through the list.

We can do this by implementing a tail-recursive function which helper, which maintains the value of the current minimum and a count of the number of times that item has appeared.

We can then wrap this in another function min_count via a let-in-end block.

For example:

fun min_count [] = 0 (* the empty list has zero items in it *)
  | min_count (x :: xs) =
let
  (* when we reach the end of the list, return the accumulated count *)
  fun helper (_, n) [] = n
    | helper (m, n) (y :: ys) =

    (* if we find a new minimum, reset the count *)
    if y < m then helper (y, 1) ys

    (* if the current list item is larger than the min, ignore it *)
    else if y > m then helper (m, n) ys

    (* if we've found another instance of the min, add one to the count *)
    else helper (m, n   1) ys
in
  (* first item appears once *)
  helper (x, 1) xs (* first item appears once *)
end;

CodePudding user response:

We can also readily define this in terms of a fold.

What information do we need to keep track of as we fold over the list?

  • The current minimum.
  • The current count of minimum values.

Using List.foldl this will be our initial value expressed as a tuple. We'll pick the maximum value an int can be (at least on my machine). Feel free to change this value as is sensible. And we'll start with a count of zero.

let
  fun f(x, (min, count)) =
    if x = min then (min, count   1) 
    else if x < min then (x, 1)
    else (min, count)
in
  List.foldl f (1073741823, 0) [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 3, 3, 5]
end;

The function we apply each time is very simple. It patterns matches against that initial value tuple to give us min and count. If min equals the current value in the list (x) then x is another occurrence of that minimum value and we increment the count by 1. If it's less than the min then we have a new minimum value, so we pass that along and start over at 1 with the count. Otherwise, nothing changes.

Optionally we can clean this up a bit using Int.compare, case, and aliasing (min, count) as init.

let
  fun f(x, init as (min, count)) =
    case Int.compare(x, min) of
      EQUAL => (x, count   1)
    | LESS  => (x, 1)
    | _     => init

  val init = (1073741823, 0)
  val lst  = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 3, 3, 5]
in
  List.foldl f init lst
end;
  • Related