【问题标题】:F# solution without mutation没有突变的 F# 解决方案
【发布时间】:2019-03-21 05:32:12
【问题描述】:

只是为了好玩,我阅读了these 面试问题并试图在 C# 和 F# 中找到解决方案,但我很难在不改变布尔值或使用正则表达式的情况下遵循惯用的 F#:

给定一个包含一个或多个 $ 符号的字符串,例如: “富吧富$吧$富吧$” 问题:如何从给定字符串中删除第二次和第三次出现的 $?

我的带有突变的命令式 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

(还有一个 C#):

var input = "foo bar foo $ bar $ foo bar $ ";
var sb = new StringBuilder();
bool first = true;
input.ForEach(c => {
    switch (c)
    {
        case '$' when first: first = false; break;
        default: sb.Append(c);break;
    };
});

【问题讨论】:

    标签: .net f# functional-programming c#-to-f# mutation


    【解决方案1】:
    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 $"
    

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

    【讨论】:

    • 没错!我正在玩匹配,但无法完成。您的解决方案实际上让我意识到,我读错了问题并且删除了第一个问题而不是其他问题,所以也感谢您。
    【解决方案2】:
    let f (s:string) =
        s.Split('$')
        |> Seq.mapi (fun i t -> (if i > 3 || i = 1 then "$" else "") + t)
        |> String.concat ""
    

    这是另一个使用 tail 递归和seq 计算表达式扫描每个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
    • 你是对的。事实上,它甚至不认为它是尾递归,可能是因为它是一个计算表达式。谢谢!
    猜你喜欢
    • 2013-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多