我正在尝试找到最常出现的模式或值。我想要一个像这样的功能:
mode:' 'a list -> (''a * int) list
它返回模式及其发生的位置,除非有一个平局然后返回所有出现的事情,如下所示:
mode([1,1,2,3,5,8]) ===> [(1,2)]
mode([1,3,5,2,3,5]) ===> [(3,2),(5,2)]
mode([true,false,true,true]) ====>[(true,3)]
我试图在SML中没有库函数的情况下这样做。
到目前为止我得到了:
fun mode(L)=
if null L then nil
else if hd L= hd (tl L) then 1+mode(hd(tl L))
else mode(tl L);
我知道这不对,我想我很好奇你们如何保持模式发生的位置和模式的索引,并将它们作为元组返回列表中。
你试图通过几个简单的练习来解决很多部分的练习。根据您目前的进展情况,您是否考虑过解决一些非常类似的练习,以达到最终目标?在解决编程问题时,这通常是一个很好的建议:将当前问题减少到更简单的问题并解决问题。
histogram : ''a list -> (''a * int) list
:
fun histogram [] = ...
| histogram (x::xs) = ...
通过将每个x
及其count
插入直方图来完成此操作。
fun insert (x, []) = ...
| insert (x, (y, count) :: hist) = ...
并编写一些可以偶尔执行的测试。mode : ''a list -> ''a
:
fun mode xs = ... (histogram xs)
通过查找具有最大计数的直方图中的元素来执行此操作:
fun findMax [] = ... (* what if the list/histogram is empty? *)
| findMax [(x, count)] = ...
| findMax ((x, count) :: (y, count) :: hist) = ...
histogram : (''a * int * int list) list
,它不仅包含每个元素的频率,还包含它们在输入列表中的位置:
fun histogram_helper ([], _) = ...
| histogram_helper (x::xs, i) = ... histogram_helper (xs, i+1) ...
通过插入每个x
及其count
并将i
与之前找到的位置is
一起插入直方图来执行此操作:
fun insert (x, i, []) = ...
| insert (x, i, (y, count, is) :: hist) = ...
mode : ''a list -> (''a * int list) list
:
fun mode xs = ... (histogram xs)
通过查找具有最大计数的直方图中的(可能是多个)元素来执行此操作:
fun findMax ([], countMax, tmpModes) = ...
| findMax ((x, count, is) :: hist, countMax, tmpModes) = ...
countMax : int
是在tmpModes : (''a * int * int list) list
重复的频率。这里countMax
和tmpModes
正在累积结果参数。这样做是通过确定(x, count, is)
是否应该被抛弃以支持所有tmpModes
,或者它应该被添加到tmpModes
,或者应该选择有利于所有tmpNodes
我很好奇你们如何保持模式发生的位置和模式的索引,并将它们作为元组返回列表中。
是的,这不是微不足道的。使用我建议的划分为子问题,回答这取决于我们是在histogram
函数还是findMax
函数:
在histogram
中,您可以将索引存储为包含元素和频率的元组的一部分。在findMax
,由于你可能收集多个结果,你需要跟踪哪个频率最高(countMax
)和临时选择的模式(tmpModes
);在稍后的递归电话中被替换或添加。
所以回答你的问题:在一个累积的参数。
fun mode(L)=
if null L then nil
else if hd L= hd (tl L) then 1+mode(hd(tl L))
else mode(tl L);
使用模式匹配而不是null
,hd
和tl
:
fun count_4s [] = 0
| count_4s (x::xs) = (if x = 4 then 1 else 0) + count_4s xs
fun count_ns ([], _) = 0
| count_ns (x::xs, n) = (if x = n then 1 else 0) + count_ns (xs, n)
fun count_12 ([], ones, twos) = (ones, twos)
| count_12 (x::xs, ones, twos) =
if x = 1 then count_12 (xs, ones+1, twos) else
if x = 2 then count_12 (xs, ones, twos+1) else
count_12 (xs, ones, twos)
fun count_abc ([], result) = result
| count_abc (x::xs, ((a, ca), (b, cb), (c, cc))) =
count_abc (xs, if x = a then ((a, ca+1), (b, cb), (c, cc)) else
if x = b then ((a, ca), (b, cb+1), (c, cc)) else
if x = c then ((a, ca), (b, cb), (c, cc+1)) else
((a, ca), (b, cb), (c, cc)))
构建直方图是对此的扩展,而不是像4
这样的固定值,或者像ones
和twos
这样的固定值,你有一个完整的列表,你必须动态地寻找你的那个得到,x
,并确定是否需要将其添加到直方图或在直方图中递增。
最好的方法是在辅助函数中执行此操作,例如,如果count_abc
是使用辅助函数创建的,
fun insert_abc (x, ((a, ca), (b, cb), (c, cc))) =
if x = a then ((a, ca+1), (b, cb), (c, cc)) else
if x = b then ((a, ca), (b, cb+1), (c, cc)) else
if x = c then ((a, ca), (b, cb), (c, cc+1)) else
((a, ca), (b, cb), (c, cc)))
fun count_abc ([], result) = result
| count_abc (x::xs, result) =
count_abc (xs, insert (x, result))
只代替直方图表示
(''a * int) * (''a * int) * (''a * int)
你要
(''a * int) list
和insert
应该是递归的,而不是insert_abc
是如何重复的。