我对F#很新。我编写了一个函数,它返回目标中子字符串匹配索引的数组,它类似于我在C#中编写的方式。
是否有更实用的方法来解决这个问题,是否可以在不使用任何可变变量的情况下解决?
let SubStringIndices (haystack:string) (needle:string) =
let mutable indices = System.Collections.Generic.List<int>()
let mutable index = haystack.IndexOf(needle)
while index >= 0 do
indices.Add(index)
index <- haystack.IndexOf(needle, index+1)
indices.ToArray()
printfn "%A" (SubStringIndices "abaabababaaab" "ab")
// prints [|0; 3; 5; 7; 11|]
我不是在寻找在每个索引处检查子字符串匹配的解决方案。
答案 0 :(得分:4)
这是一个简单的递归函数,可以执行相同的操作:
let rec subStringIndices (haystack:string) (needle:string) (from:int) =
let index = haystack.IndexOf(needle, from)
if index >= 0 then
let rest = subStringIndices haystack needle (index + 1)
index::rest
else []
printfn "%A" (subStringIndices "abaabababaaab" "ab" 0)
该函数采用另一个参数from
来表示起始索引(您希望在字符串中开始搜索的位置)。最初,将其设置为零。在函数中,我们首先得到下一个索引。如果我们找到了某些东西,我们递归处理字符串的其余部分(从index + 1
开始)并返回一个包含索引和所有递归索引的列表。
使用累加器参数技巧和嵌套函数可以编写使用 tail-recursion 的更优雅,更高效的版本:
let subStringIndices (haystack:string) (needle:string) =
let rec loop (from:int) acc =
let index = haystack.IndexOf(needle, from)
if index >= 0 then
loop (index + 1) (index::acc)
else
List.rev acc
loop 0 []
递归循环现在由loop
函数实现。它从外部获取haystack
和needle
作为参数,因此不需要在堆栈中复制这些参数。我们在作为参数传递的acc
列表中累积索引,当我们到达结尾时,我们返回列表(相反,因为我们在前面添加了新项目)。
答案 1 :(得分:4)
类似
let SubStringIndices (haystack:string) (needle:string) =
-1 |> Seq.unfold (fun n ->
let idx = haystack.IndexOf(needle, n + 1)
if idx <> -1 then Some(idx, idx) else None
)