在SML中,如何使用递归计算字符串中字符的出现次数? 输出应采用(char,#AppearenceOfChar)的形式。 我设法做的是
fun frequency(x) = if x = [] then [] else [(hd x,1)]@frequency(tl x)
将返回表格(char,1)的tupels。我也可以删除此列表中的重复项,因此我现在未能做的就是编写像
这样的函数 fun count(s:string,l: (char,int) list)
'迭代'通过增加特定tupel组件的字符串。我怎么能递归地做到这一点?抱歉没有问题,但我是函数式编程的新手,但我希望这个问题至少可以理解:)
答案 0 :(得分:0)
我将问题分解为两个:增加单个字符的频率,迭代字符串中的字符并插入每个字符。增加频率取决于你之前是否已经看过这个角色。
fun increaseFrequency (c, []) = [(c, 1)]
| increaseFrequency (c, ((c1, count)::freqs)) =
if c = c1
then (c1, count+1)
else (c1,count)::increaseFrequency (c, freqs)
这提供了具有以下类型声明的函数:
val increaseFrequency = fn : ''a * (''a * int) list -> (''a * int) list
因此,给定一个字符和一个频率列表,它会返回一个更新的频率列表,其中字符已插入频率为1,或者其现有频率已增加1,方法是对每个元组执行线性搜索,直到要么找到正确的,要么满足列表的结尾。保留所有其他字符频率。
迭代字符串中字符的最简单方法是将explode
转换为字符列表,并将每个字符插入以空列表开头的累积频率列表中:
fun frequencies s =
let fun freq [] freqs = freqs
| freq (c::cs) freqs = freq cs (increaseFrequency (c, freqs))
in freq (explode s) [] end
但这不是一次迭代一个字符串的非常有效的方法。或者,您可以通过索引访问每个字符,而无需转换为列表:
fun foldrs f e s =
let val len = size s
fun loop i e' = if i = len
then e'
else loop (i+1) (f (String.sub (s, i), e'))
in loop 0 e end
fun frequencies s = foldrs increaseFrequency [] s
您可能还会考虑使用比列表更有效的集合表示来减少线性时间插入。