避免迭代的最佳方法
Best way to avoid iteration
我有一个字符串
testString = "Hello [1], my name is [2]"
我想替换它所以它等于
Hello Maria, my name is My.
我有一个接受字符串和替换列表的函数。然后遍历该列表,根据需要进行替换。
let parse testString (replacements: list<string>) =
let mutable result = testString
for index = 1 to replacements.Length do
result <- result.Replace("[" + (index).ToString() + "]", replacements.[index-1])
result
parse testString ["Maria";"My"]
但由于我切换到 F# 的主要原因之一是避免迭代和可变性,解决这个问题的最佳方法是什么?
我考虑过在字符串上使用 Regex 替换回调或在结果列表上使用 iter/map(似乎是最好的方法)。
您可以通过以下几种方法在更惯用的 F# 中解决问题:
let testString = "Hello [1], my name is [2]"
let parse input replacements =
replacements
|> List.mapi (fun i s -> i + 1, s) //Create a tuple with the index and the string
|> List.fold (fun (result: string) (i, s) -> result.Replace($"[{i}]", s)) input //Fold iterates through the list making the replacements recursively
let parse2 input replacements =
let rec parse2' (input:string) (replacements:string list) i =
match replacements with
| [] -> input //Replacements are empty so return the input
| s :: replacements ->
// Take the head element off the list using pattern matching
// Make a recursive call after performing the replacement
parse2' (input.Replace($"[{i}]", s)) replacements (i + 1)
parse2' input replacements 1
printfn "%s" (parse testString [ "Maria"; "My" ])
printfn "%s" (parse2 testString [ "Maria"; "My" ])
请注意,您的代码没有什么特别的问题,F# 鼓励采用混合方法来解决问题。如果您限制它们的范围,可变性和 'raw' 迭代就没有问题。在这种情况下,变量永远不会离开函数的范围,因此它与程序的其余部分无关。
在等待 Tranquility 的积极回应的同时,我也确实想出了一个方法来自己做匹配评估器和正则表达式,如果这对任何人都有用的话。
let parseReplacements (matchedIndex: Match) (replacements: list<string>) =
let indexString = matchedIndex.Groups.[1] |> string
let index = (indexString |> int) - 1
if index <= replacements.Length then
replacements.[index]
else
"[" + indexString + "]"
let parse input (replacements: list<string>) =
Regex.Replace(input, "\[(\d+)\]", new MatchEvaluator(fun matched -> parseReplacements matched replacements))
我有一个字符串
testString = "Hello [1], my name is [2]"
我想替换它所以它等于
Hello Maria, my name is My.
我有一个接受字符串和替换列表的函数。然后遍历该列表,根据需要进行替换。
let parse testString (replacements: list<string>) =
let mutable result = testString
for index = 1 to replacements.Length do
result <- result.Replace("[" + (index).ToString() + "]", replacements.[index-1])
result
parse testString ["Maria";"My"]
但由于我切换到 F# 的主要原因之一是避免迭代和可变性,解决这个问题的最佳方法是什么?
我考虑过在字符串上使用 Regex 替换回调或在结果列表上使用 iter/map(似乎是最好的方法)。
您可以通过以下几种方法在更惯用的 F# 中解决问题:
let testString = "Hello [1], my name is [2]"
let parse input replacements =
replacements
|> List.mapi (fun i s -> i + 1, s) //Create a tuple with the index and the string
|> List.fold (fun (result: string) (i, s) -> result.Replace($"[{i}]", s)) input //Fold iterates through the list making the replacements recursively
let parse2 input replacements =
let rec parse2' (input:string) (replacements:string list) i =
match replacements with
| [] -> input //Replacements are empty so return the input
| s :: replacements ->
// Take the head element off the list using pattern matching
// Make a recursive call after performing the replacement
parse2' (input.Replace($"[{i}]", s)) replacements (i + 1)
parse2' input replacements 1
printfn "%s" (parse testString [ "Maria"; "My" ])
printfn "%s" (parse2 testString [ "Maria"; "My" ])
请注意,您的代码没有什么特别的问题,F# 鼓励采用混合方法来解决问题。如果您限制它们的范围,可变性和 'raw' 迭代就没有问题。在这种情况下,变量永远不会离开函数的范围,因此它与程序的其余部分无关。
在等待 Tranquility 的积极回应的同时,我也确实想出了一个方法来自己做匹配评估器和正则表达式,如果这对任何人都有用的话。
let parseReplacements (matchedIndex: Match) (replacements: list<string>) =
let indexString = matchedIndex.Groups.[1] |> string
let index = (indexString |> int) - 1
if index <= replacements.Length then
replacements.[index]
else
"[" + indexString + "]"
let parse input (replacements: list<string>) =
Regex.Replace(input, "\[(\d+)\]", new MatchEvaluator(fun matched -> parseReplacements matched replacements))