SML,如何查找列表中最小数量的出现次数?

Posted

技术标签:

【中文标题】SML,如何查找列表中最小数量的出现次数?【英文标题】:SML, How to find number of occurrences of the minimum number in a list? 【发布时间】:2021-12-27 23:37:11 【问题描述】:

在 SML 中是否可以在列表中找到最小数字的出现次数?

我有代码可以找到一个数字的出现次数,但我不知道如何找到最小值并使用它来找到有多少个最小值。

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

谢谢!

【问题讨论】:

【参考方案1】:

您可以编写一个函数,在您遍历列表时跟踪最小值及其计数。

我们可以通过实现一个尾递归函数helper 来做到这一点,它维护当前最小值的值和该项目出现次数的计数。

然后我们可以通过 let-in-end 块将其包装在另一个函数 min_count 中。

例如:

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;

【讨论】:

谢谢!我将如何运行这段代码?【参考方案2】:

这个问题是在列表上使用折叠的一个很好的测试。

寻找最小值

如果我们想在列表中找到最小值,我们需要遍历列表,检查每个元素是否与预先确定的起始最小值相符。如果该元素小于已知最小值,我们将继续使用该值进行迭代。完成后,我们就有了最小值。

如果列表为空,则没有最小值。如果列表中只有一个值,则最小值显然是该值。如果有多个值,则起始最小值是第一个元素。

我们可以使用foldl 来处理最后一种情况的迭代。

fun min([]) = NONE
  | min([x]) = SOME x
  | min(first::rest) = 
    SOME (foldl (fn (x, min) => if x < min then x else min) 
                first rest)

发现事件

您已经这样做了,但这也可以通过折叠来完成。

fun occurrences(lst, v) =
  foldl (fn (x, count) => if x = v then count + 1 else count) 
        0 lst

把这些放在一起

我们可以使用这两个函数来查找最小值在列表中出现的次数。

let
  val numbers = [1, 4, 7, 2, 9, 0, 1, 6, 0]
  val min = min(numbers)
  val occ = case min of
    NONE => NONE
  | SOME x => SOME (occurrences(numbers, x))
in
  case (min, occ) of
    (NONE, NONE) => print("No minimum found.") 
  | (SOME m, SOME t) => print("Min: " ^ Int.toString(m) ^ "; times: " ^ Int.toString(t))
end

我们可以一次性完成吗?

使用上述方法,我们必须对列表进行两次迭代。这是一种更通用但效率较低的方法,可以让这两条信息都达到最小值和出现次数。我们可以使用foldl 来获取这两条信息,它看起来很像min 的定义。

我们只需将一个函数传递给foldl,它会记录找到最小值的次数,我们需要传递一个包含初始最小值和初始计数的元组1.

fun minCount([]) = NONE 
  | minCount([x]) = SOME (x, 1)
  | minCount(first::rest) = 
    SOME (foldl (fn (x, init as (min, count)) => 
                  case Int.compare(x, min) of
                    EQUAL => (min, count + 1)
                  | LESS  => (x, 1)
                  | _     => init)
                (first, 1)
                rest)

定义了这个函数,我们之前的代码可以改写为:

let
  val numbers = [1, 4, 7, 2, 9, 0, 1, 6, 0]
  val mc = minCount(numbers)
in
  case mc of
    NONE => print("No minimum found.") 
  | SOME (m, t) => print("Min: " ^ Int.toString(m) ^ "; times: " ^ Int.toString(t))
end

【讨论】:

【参考方案3】:

假设您应该在解决方案中使用occurrences 函数,请编写一个找到最小值的函数,

fun minimum [x] = x
  | minimum (x::xs) = let 
                        val min = minimum xs 
                      in 
                        if x < min then x else min 
                      end

请注意,这不处理空列表。 您需要决定是否将丢失的模式作为运行时错误保留,或者添加它并处理错误,例如通过引发异常或将返回类型更改为int option。 如果您正在学习课程,请使用您目前所学的方法之一。

那你就可以使用那个功能了,

occurrences(the_list, minimum the_list)

【讨论】:

以上是关于SML,如何查找列表中最小数量的出现次数?的主要内容,如果未能解决你的问题,请参考以下文章

如何获取数组中出现次数最多的字符串?

vim怎么正则查询一个词出现的次数

排列并查找列表中出现次数最多的项目

如何计算Dataframe中,列中元素连续出现次数

过滤掉出现次数少于最小阈值的元素

搜索排序数组中出现次数超过一半的元素所需的最小比较