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

时间:2016-04-24 21:10:44

标签: arrays recursion f# pattern-matching calculator

我尝试使用两个数组在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

2 个答案:

答案 0 :(得分:1)

在回答@Liam Donnelly回答他自己的问题时:我会抛开诸如“这是解决问题的最佳方法”之类的问题,只是评论如何更好地编写您目前拥有的代码。

数组切片和连接方式在此处可以写成

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>

此外,如果您不认识运营商,则返回“默认结果”是我认为非常危险的事情(即使这种做法相当普遍)

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

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

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

答案 1 :(得分:0)

我已经成功完成了执行我需要的任务的功能,并且我确信通过使用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])