从数组中取出两个元素并添加它们,然后将它们添加回数组

Taking two elements from an array and adding them, then adding them back into the array

我正在尝试使用两个数组在 f# 中创建一个计算器,一个用于存储数字,另一个用于存储运算符符号。我需要符号数组来模式匹配符号,并根据运算符从数组中取出前两个元素并执行操作并将新数字添加到第二个数组的头部。

open System

[<EntryPoint>]
let main argv = 
printfn "%A" argv

let Add x y = x + y
let Sub x y = x - y
let Div x y = x * y
let Mul x y = x / y

printfn "1 > Calculator \n2 > Load from txt file"

let chosenIn = Console.ReadLine();

//This is where I need to do the operation and after call the sum function 
//again until there's only one element left in the number array
let rec sum num (numArray : int[]) sym (symArray : string[]) () =



let rec calc () = 
    printfn "Enter Sum"
    let input = Console.ReadLine()
    let intInput = input.Split()
    let numArray = [|for num in intInput do
                        let v , vp = System.Int32.TryParse(num)
                        if v then yield vp|]

    let symbolArray = [|for symbol in intInput do
                        match symbol with 
                        | "+" -> yield symbol
                        | "-" -> yield symbol
                        | "/" -> yield symbol
                        | "*" -> yield symbol
                        | _ -> ignore 0|]

    calc()

match chosenIn with
| "1" -> calc()
| "2" -> printfn "File"
| _ -> printfn "Invalid"

0 // return an integer exit code

我已经成功地创建了执行我需要的任务的函数,我确信有一种代码效率更高的方法来使用 Array.copy 来获取数组的第一个元素使用过滤器,但我是 f# 的新手,所以我只是按照我有信心的方式使用

let rec sum (numArray : int[]) (symArray : string[])  =
    let result = match symArray.[0] with
                 | "+" -> Add numArray.[0] numArray.[1]
                 | "-" -> Sub numArray.[0] numArray.[1]
                 | "*" -> Mul numArray.[0] numArray.[1]
                 | _ -> 0

    let newNumArray = [|
                        for i = 0 to numArray.Length - 1 do
                            if i = 0 then yield result
                            if i > 1 then yield numArray.[i]|]

    let newSymArray = [|
                        for i = 0 to symArray.Length - 1 do
                            if i > 0 then yield symArray.[i]|]

    if newNumArray.Length > 1 then
        sum newNumArray newSymArray
    else
        for i = 0 to newNumArray.Length - 1 do
            printfn "%i" (newNumArray.[i])

回应@Liam Donnelly 对他自己的问题发表的回答:我将搁置诸如 "is that really the best way of solving the problem" 之类的问题,仅评论如何更好地编写您当前拥有的代码。

数组切片和连接你在这里做的方式可以写成

let newNumArray = Array.append [| result |] numArray.[2..]

但是,我会使用 F# 列表而不是数组来完成您的任务。使用列表,您可以进行模式匹配以访问前 2 个元素。在我看来,模式匹配胜过直接索引,因为您可以直接对极端情况进行编码,并让 F# 编译器提醒您极端情况。对操作员做同样的事情。您可以同时执行运算符和操作数。然后它看起来像这样:

let rec sum2 (numArray : int list) (symArray : string list)  =
    let newNum, newSym = 
        match numArray with
        | [] -> failwith "No numbers left to process"
        | arg1 :: [] -> failwith "There's only one number left to process"
        | arg1 :: arg2 :: args -> 
            match symArray with
            | op1 :: ops ->
                let result = 
                    match op1 with
                    | "+" -> Add arg1 arg2
                    | "-" -> Sub arg1 arg2
                    | "*" -> Mul arg1 arg2
                    | _ -> failwithf "Operator not recognized: '%s'" op1
                // Return the result, concatenate the non-processed 
                // numbers. Return the non-processed operators
                result :: args, ops
            | _ -> failwith "I've run out of operators?"
<snip>

此外,如果您不认识运算符,则返回 "default result" 是我认为非常冒险的事情(尽管这种做法相当普遍)

如果您使用列表(即 F# 列表),您可以通过 head 直接访问索引 1.. 处的元素:let newSymArray = symArray.Head 或使用 List.head

每当您看到自己在 F# 中编写 for 循环时,请后退一步。它们编写起来很麻烦并且容易出错。 F# 库函数涵盖了循环的大多数典型用例,因此请仔细阅读这些内容。可以通过以下方式缩短打印循环:

newNumArray
|> Seq.iter (printfn "%i")