.net 无突变的F#解

.net 无突变的F#解,.net,f#,functional-programming,c#-to-f#,mutation,.net,F#,Functional Programming,C# To F#,Mutation,只是为了好玩,我阅读了采访问题,并试图在C#和F#中找到解决方案,我很难在惯用F#中做到以下几点,而不改变布尔值或使用正则表达式: 您会收到一个包含一个或多个$symbol的单词字符串,例如: “foo bar foo$bar$foo bar$” 问题:如何从给定字符串中删除第二次和第三次出现的$? 我的强制性F#突变解决方案: let input = "foo bar foo $ bar $ foo bar $ " let sb = new StringBuilder() let mutabl

只是为了好玩,我阅读了采访问题,并试图在C#和F#中找到解决方案,我很难在惯用F#中做到以下几点,而不改变布尔值或使用正则表达式:

您会收到一个包含一个或多个$symbol的单词字符串,例如: “foo bar foo$bar$foo bar$” 问题:如何从给定字符串中删除第二次和第三次出现的$?

我的强制性F#突变解决方案:

let input = "foo bar foo $ bar $ foo bar $ "
let sb = new StringBuilder()
let mutable first = true

let f c=
    if c='$' && first then first<-false
    else sb.Append(c) |> ignore

input |> Seq.iter f
请注意,此解决方案仅删除
$
的第二个和第三个实例。如果要删除除第一个以外的所有内容,请将
String.concat“$”替换为
String.concat”“

这是另一个使用尾部递归和计算表达式扫描每个
char

let f (s:string) =
    let rec chars n input = seq {
        match Seq.tryHead input with
        | Some '$' ->   if not(n = 1 || n = 2) then yield  '$'
                        yield! Seq.tail input |> chars (n+1)
        | Some c   ->   yield  c
                        yield! Seq.tail input |> chars n
        | None     ->   ()
    }
    chars 0 s
    |> fun cs -> new string(Seq.toArray cs)
它可能更长,但可能比第一个更有效


编辑:不,它不是更有效的,也不是尾部递归,可能是因为它发生在计算表达式内部。

没错!我在玩弄匹配,但没能完成。您的解决方案实际上让我意识到,我看错了问题,并且删除了第一个而不是其他的,因此也感谢您。您的第二个解决方案在使用原始示例输入时实际上慢了多个数量级。因为创建了太多的
seq
/
IEnumerable
对象,所以它似乎要进行更多的分配。为了可读性和性能,我通常会尽量避免混合使用递归和
seq
。你是对的。事实上,它甚至不认为它是一个尾部递归,可能是因为它是一个计算表达式。非常感谢。
let f (s:string) =
    s.Split('$')
    |> Array.toList
    |> function
        | [] -> ""
        | [ a ] -> a
        | [ a; b ] -> a + "$" + b
        | a :: b :: c :: rest -> a + "$" + b + c + (rest |> String.concat "$")

f "foo bar foo $ bar $ foo bar $ "
// "foo bar foo $ bar  foo bar  "

f "1 $ 2 $ 3 $ 4 $ 5 $"
//"1 $ 2  3  4 $ 5 $"
let f (s:string) =
    s.Split('$')
    |> Seq.mapi (fun i t -> (if i > 3 || i = 1 then "$" else "") + t)
    |> String.concat ""
let f (s:string) =
    let rec chars n input = seq {
        match Seq.tryHead input with
        | Some '$' ->   if not(n = 1 || n = 2) then yield  '$'
                        yield! Seq.tail input |> chars (n+1)
        | Some c   ->   yield  c
                        yield! Seq.tail input |> chars n
        | None     ->   ()
    }
    chars 0 s
    |> fun cs -> new string(Seq.toArray cs)