recursion - 在 SML 中查找 int 列表的模式以及它在没有库函数的情况下出现的位置
问题描述
我试图找到最常出现的模式或值。我想要一个类似的功能:
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
重复的。
推荐阅读
- javascript - How do I embed javascript into an IIS UrlRewrite rule?
- unit-testing - 使用 GTEST / GMOCK 对嵌入式源代码进行单元测试
- c - 拆分服务器进程的最佳方法
- android - 工具栏中的搜索图标不可见
- xpath - Xpath 中这个 BeautifulSoup 表达式的等价物是什么?
- windows - FFMPEG xstack无法识别输入
- linux-kernel - 从源代码编译 Android 内核模块
- wordpress - Wordpress 产品页面自动更改为每行 1 个产品
- c - 为什么我们不能为结构的成员设置默认值?
- c++ - 在 C++ 中使用成员函数的轻量级方法