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,如何查找列表中最小数量的出现次数?的主要内容,如果未能解决你的问题,请参考以下文章