我正在构建一个函数,该函数在nth
位置之后的字符串中出现多次字符数。
countCh ("aaabbbccc", 3, 'b')
val it: int = 2
在C
中,我会使用带有while
循环的累加器。但我正在努力学习F#功能面,不鼓励这种方法。
所以我使用警卫来测试几个条件并构建函数:
let rec countCh (s:string, n:int, ch:char) =
match s, n, ch with
| (s, n, ch) when n > s.Length -> 0 //p1
| (s, n, ch) when n < 0 -> 0 //p2
| (s, n, ch) when s.[n] <> ch -> countCh(s, n + 1, ch) //p3
| (s, n, ch) when s.[n] = ch -> 1 + countCh(s, n + 1, ch) //p4
模式3
和4
的共存是有问题的(恐怕不可能)。即使它编译,我也无法使它工作。如何在功能上处理这项任务?
答案 0 :(得分:4)
首先,这些分支的共存不成问题。它们不会相互冲突。为什么你认为它有问题?是因为您收到“不完整模式匹配”编译器警告?该警告并未告诉您分支冲突,它告诉您编译器无法证明四个分支涵盖所有可能性。或者你认为这是出于其他原因吗?如果您希望准确回答问题,则必须更清楚地询问他们。
其次,你在滥用模式匹配。看:没有图案!每个分支中的模式完全相同,而且是微不足道的。只有警卫是不同的。这在match
内看起来非常违反直觉,但可以用if..elif
明确表达:
let rec countCh (s:string) n ch =
if n >= s.Length || n < 0 then 0
elif s.[n] = ch then 1 + countCh s (n + 1) ch
else countCh s (n + 1) ch
注意1 :看看我如何将参数调整为咖喱?除非有非常强烈的理由使用tupled,否则始终使用curried形式。咖喱参数在呼叫方使用起来更加方便。
注意2 :您的条件n > s.Length
不正确:字符串索引从0
转到s.Length-1
,因此保释条件应为n >= s.Length
。它已在我的代码中得到纠正。
最后,由于这是一个练习,我必须指出递归不是 tail 递归。查看第二个分支(在我的代码中):它以递归方式调用函数,然后在结果中添加一个。由于您必须对递归调用的结果执行某些操作,因此递归不能是“ tail ”。这意味着您在很长的输入上存在堆栈溢出的风险。
要将其转换为 tail 递归,您需要将函数“内向外”,这样说。您不需要从每次调用返回结果,而是需要将传递给每个调用(也称为“累加器”),并且只从终端案例返回:
let rec countCh (s:string) n ch countSoFar =
if n >= s.Length || n < 0 then countSoFar
elif s.[n] = ch then countCh s (n+1) ch (countSoFar+1)
else countCh s (n+1) ch countSoFar
// Usage:
countCh "aaaabbbccc" 5 'b' 0
这样,每个递归调用都是“最后一次”调用(即函数不对结果做任何事情,而是直接将其传递给自己的调用者)。这称为“尾递归”,可以编译为在常量堆栈空间中工作(而不是线性)。
答案 1 :(得分:2)
我建议不要自己写,但要求图书馆功能寻求帮助:
let countCh (s: string, n, c) =
s.Substring(n+1).ToCharArray()
|> Seq.filter ((=) c)
|> Seq.length
或者使用Seq.skip
,以及您可以将转换删除到字符数组的事实:
let countCh (s: string, n, c) =
s
|> Seq.skip (n + 1)
|> Seq.filter ((=) c)
|> Seq.length
答案 2 :(得分:2)
我同意其他答案,但我想帮助您解决原始问题。你需要缩进该函数,并且你有一个错误:
let rec countCh (s:string, n:int, ch:char) =
match s, n, ch with
| s, n, _ when n >= s.Length-1 -> 0 //p1
| s, _, _ when n < 0 -> 0 //p2
| s, n, ch when s.[n+1] <> ch -> countCh(s, n+2, ch) //p3
| s, n, ch when s.[n+1] = ch -> 1 + countCh(s, n+2, ch) //p4