Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/date/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何以正确的顺序执行乘法和/或除法?_Swift - Fatal编程技术网

Swift 如何以正确的顺序执行乘法和/或除法?

Swift 如何以正确的顺序执行乘法和/或除法?,swift,Swift,我正在做一个简单的计算器,但在执行乘法和除法时,我的代码并没有使它们优先于加号和减号。 执行->2+2*4时,结果为16而不是10。。。 如何符合switch语句中的数学逻辑 mutating func calculateTotal() -> Double { var total: Double = 0 for (i, stringNumber) in stringNumbers.enumerated() { if let number = Double(stringNum

我正在做一个简单的计算器,但在执行乘法和除法时,我的代码并没有使它们优先于加号和减号。 执行->2+2*4时,结果为16而不是10。。。 如何符合switch语句中的数学逻辑

mutating func calculateTotal() -> Double {
  var total: Double = 0
  for (i, stringNumber) in stringNumbers.enumerated() {
    if let number = Double(stringNumber) {
      switch operators[i] {
      case "+":
        total += number
      case "-":
        total -= number
      case "÷":
        total /= number
      case "×":
        total *= number
      default:
        break
      }
    }
  }
  clear()
  return total
}

首先,您必须在数组中搜索,以查看是否有÷或×符号

你可以直接求和或减法

mutating func calculateTotal() -> Double {
  var total: Double = 0
  for (i, stringNumber) in stringNumbers.enumerated() {
    if let number = Double(stringNumber) {
      switch operators[i] {
      case "÷":
        total /= number
      case "×":
        total *= number
      default:
        break
      }
      //Remove the number from the array and make another for loop with the sum and subtract operations.

    }
  }
  clear()
  return total
}

如果您不使用复数,这将起作用。

如果您只有四个操作
+
-
x
÷
,则可以在遇到
+
-
时跟踪
挂起操作和
挂起操作

然后在遇到另一个
+
-
时,或在计算结束时,计算挂起的操作。请注意,
+
-
计算挂起的操作,但随后立即启动一个新操作

我已经修改了您的函数,将
stringNumbers
运算符
初始值
作为输入,以便可以在操场上独立测试

func calculateTotal(stringNumbers: [String], operators: [String], initial: Double) -> Double {

    func performPendingOperation(operand: Double, operation: String, total: Double) -> Double {
        switch operation {
        case "+":
            return operand + total
        case "-":
            return operand - total
        default:
            return total
        }
    }

    var total = initial
    var pendingOperand = 0.0
    var pendingOperation = ""

    for (i, stringNumber) in stringNumbers.enumerated() {
        if let number = Double(stringNumber) {
            switch operators[i] {
            case "+":
                total = performPendingOperation(operand: pendingOperand, operation: pendingOperation, total: total)
                pendingOperand = total
                pendingOperation = "+"
                total = number
            case "-":
                total = performPendingOperation(operand: pendingOperand, operation: pendingOperation, total: total)
                pendingOperand = total
                pendingOperation = "-"
                total = number
            case "÷":
                total /= number
            case "×":
                total *= number
            default:
                break
            }
        }
    }

    // Perform final pending operation if needed
    total = performPendingOperation(operand: pendingOperand, operation: pendingOperation, total: total)

    // clear()
    return total
}

测试:

// 4 + 3    
calculateTotal(stringNumbers: ["3"], operators: ["+"], initial: 4)

假设您希望为任何算术表达式提供一个通用且可能可扩展的算法,正确的方法是使用

您有一个输入流,它是用户键入的数字和运算符,您有一个输出流,它是相同的数字和运算符,但重新排列为反向波兰符号。因此,例如,
2+2*4
将被转换为
2+2*4*+
,通过在读取时将数字放在堆栈上,并在读取时将运算符应用于堆栈顶部的项目,可以轻松计算出该值

为此,该算法有一个操作员堆栈,可以将其可视化为侧线(因此称为“调车场”),低优先级操作员将被调到该侧线中,直到需要他们为止

一般算法是

  • 从输入中读取项目
  • 如果是数字,则将其发送到输出
  • 如果号码是运算符,则
    • 虽然堆栈顶部的运算符的优先级高于已在堆栈上弹出的运算符,并将其发送到输出
    • 将从输入中读取的运算符推送到堆栈上
  • 重复上述步骤,直到输入为空
  • 将堆栈上的所有运算符弹出到输出中
因此,如果您有
2+2*4
(注意堆栈顶部在左侧,堆栈底部在右侧)

开始:
输入:2+2*4
输出:
堆栈:
步骤1:将2发送到输出
输入:+2*4
产出:2
堆栈:
步骤2:堆栈为空,因此将+放在堆栈上
输入:2*4
产出:2
堆栈:+
步骤3:将2发送到输出
输入:*4
产出:2
堆栈:+
步骤4:+的优先级比*低,所以只需将*放在堆栈上即可
投入:4
产出:2
堆栈:*+
步骤5:将4发送到输出
输入:
产出:2 4
堆栈:*+
步骤6:输入为空,因此弹出堆栈以输出
输入:
产出:2 4*+
堆栈:
上面我链接的Wikipedia条目有更详细的描述和一个可以处理括号和函数调用的算法,并且更具可扩展性


为了完整起见,这里是我的算法简化版本的一个实现

enum Token: CustomStringConvertible
{
    var description: String
    {
        switch self
        {
        case .number(let num):
            return "\(num)"
        case .op(let symbol):
            return "\(symbol)"
        }
    }

    case op(String)
    case number(Int)

    var precedence: Int
    {
        switch self
        {
        case .op(let symbol):
            return Token.precedences[symbol] ?? -1
        default:
            return -1
        }
    }
    var operation: (inout Stack<Int>) -> ()
    {
        switch self
        {
        case .op(let symbol):
            return Token.operations[symbol]!
        case .number(let value):
            return { $0.push(value) }
        }
    }
    static let precedences = [ "+" : 10, "-" : 10, "*" : 20, "/" : 20]
    static let operations: [String : (inout Stack<Int>) -> ()] =
    [
        "+" : { $0.push($0.pop() + $0.pop()) },
        "-" : { $0.push($0.pop() - $0.pop()) },
        "*" : { $0.push($0.pop() * $0.pop()) },
        "/" : { $0.push($0.pop() / $0.pop()) }
    ]
}

struct Stack<T>
{
    var values: [T] = []

    var isEmpty: Bool { return values.isEmpty }
    mutating func push(_ n: T)
    {
        values.append(n)
    }

    mutating func pop() -> T
    {
        return values.removeLast()
    }

    func peek() -> T
    {
        return values.last!
    }
}

func shuntingYard(input: [Token]) -> [Token]
{
    var operatorStack = Stack<Token>()
    var output: [Token] = []

    for token in input
    {
        switch token
        {
        case .number:
            output.append(token)
        case .op:
            while !operatorStack.isEmpty && operatorStack.peek().precedence >= token.precedence
            {
                output.append(operatorStack.pop())
            }
            operatorStack.push(token)
        }
    }
    while !operatorStack.isEmpty
    {
        output.append(operatorStack.pop())
    }
    return output
}

let input: [Token] = [ .number(2), .op("+"), .number(2), .op("*"), .number(4)]
let output = shuntingYard(input: input)

print("\(output)")

var dataStack = Stack<Int>()

for token in output
{
    token.operation(&dataStack)
}

print(dataStack.pop())
enum令牌:CustomStringConverable
{
变量说明:字符串
{
切换自身
{
案例编号(let num):
返回“\(num)”
case.op(let符号):
返回“\(符号)”
}
}
案例op(字符串)
案件编号(Int)
变量优先级:Int
{
切换自身
{
case.op(let符号):
返回标记。先例[符号]??-1
违约:
返回-1
}
}
变量操作:(输入输出堆栈)->()
{
切换自身
{
case.op(let符号):
返回令牌。操作[符号]!
案例编号(let值):
返回{$0.push(值)}
}
}
静态let优先级=[“+”:10,“-”:10,“*”:20,“/”:20]
静态let操作:[字符串:(输入输出堆栈)->()]=
[
“+”:{$0.push($0.pop()+$0.pop())},
“-”:{$0.push($0.pop()-$0.pop())},
“*”:{$0.push($0.pop()*$0.pop())},
“/”:{$0.push($0.pop()/$0.pop())}
]
}
结构堆栈
{
变量值:[T]=[]
var isEmpty:Bool{return values.isEmpty}
变异函数推送(n:T)
{
值。追加(n)
}
变异函数pop()->T
{
返回值。removeLast()
}
func peek()->T
{
返回值。最后!
}
}
func调车场(输入:[令牌])->[令牌]
{
var operatorStack=Stack()
变量输出:[令牌]=[]
用于输入中的令牌
{
交换令牌
{
案件编号:
output.append(令牌)
案例.op:
while!operatorStack.isEmpty&&operatorStack.peek().preference>=token.preference
{
append(operatorStack.pop())
}
运算符堆栈推送(令牌)
}
}
while!operatorStack.isEmpty
{
append(operatorStack.pop())
}
返回输出
}
让输入:[令牌]=[.number(2),.op(“+”),.number(2),.op(“*”),.number(4)]
让输出=调车场(输入:输入)
打印(“\(输出)”)
var dataStack=Stack()
用于输出中的令牌
{
token.operation(&dataStack)
}
打印(dataStack.pop())

如果你不在乎速度,因为它是由计算机运行的,你可以用机器的方式来处理它。只需选择一个可行的计算,然后重复,直到每个计算完成

只是为了好玩。我使用了一些愚蠢的变量和函数名

  func evaluate(_ values: [String]) -> String{
        switch values[1] {
        case "+": return String(Int(values[0])! + Int(values[2])!)
        case "-": return String(Int(values[0])! - Int(values[2])!)
        case "×": return String(Int(values[0])! * Int(values[2])!)
        case "÷": return String(Int(values[0])! / Int(values[2])!)
        default: break;
        }
        return "";
    }

    func oneTime(_  string: inout String, _ strings: [String]) throws{
    if let first = try NSRegularExpression(pattern:  "(\\d+)\\s*(\(strings.map{"\\\($0)"}.joined(separator: "|")))\\s*(\\d+)", options: []).firstMatch(in: string , options: [], range: NSMakeRange(0, string.count)) {
    let tempResult = evaluate((1...3).map{ (string as NSString).substring(with: first.range(at: $0))})
       string.replaceSubrange(  Range(first.range(at: 0), in: string)!  , with: tempResult)
        }
    }

    func recursive(_ string: inout String, _ strings: [String]) throws{
        var count : Int!
        repeat{ count = string.count ; try oneTime(&string, strings)
        } while (count != string.count)
    }

    func final(_ string: inout String, _ strings: [[String]])  throws -> String{
       return try strings.reduce(into: string) { (result, signs) in
            try recursive(&string, signs)
        }}

    var string = "17 - 23 + 10 + 7 ÷ 7"
    try final(&string, [["×","÷"],["+","-"]])
    print("result:" + string)
使用JeremyP方法a
12
// 2 + 2 × 4
calculateTotal(stringNumbers: ["2", "4"], operators: ["+", "×"], initial: 2)
10
// 2 × 2 + 4
calculateTotal(stringNumbers: ["2", "4"], operators: ["×", "+"], initial: 2)
8
// 17 - 2 × 3 + 10 + 7 ÷ 7
calculateTotal(stringNumbers: ["2", "3", "10", "7", "7"], operators: ["-", "×", "+", "+", "÷"], initial: 17)
22
start:
    input: 2 + 2 * 4
    output: <empty>
    stack: <empty>

step 1: send the 2 to output
    input: + 2 * 4
    output: 2
    stack: <empty>

step 2: stack is empty so put + on the stack
    input: 2 * 4
    output: 2
    stack: +

step 3: send the 2 to output
    input: * 4
    output: 2 2
    stack: +

step 4: + is lower priority than * so just put * on the stack
    input: 4
    output: 2 2
    stack: * +

step 5: Send 4 to output
    input:
    output: 2 2 4
    stack: * +

step 6: Input is empty so pop the stack to output
    input:
    output: 2 2 4 * +
    stack:

enum Token: CustomStringConvertible
{
    var description: String
    {
        switch self
        {
        case .number(let num):
            return "\(num)"
        case .op(let symbol):
            return "\(symbol)"
        }
    }

    case op(String)
    case number(Int)

    var precedence: Int
    {
        switch self
        {
        case .op(let symbol):
            return Token.precedences[symbol] ?? -1
        default:
            return -1
        }
    }
    var operation: (inout Stack<Int>) -> ()
    {
        switch self
        {
        case .op(let symbol):
            return Token.operations[symbol]!
        case .number(let value):
            return { $0.push(value) }
        }
    }
    static let precedences = [ "+" : 10, "-" : 10, "*" : 20, "/" : 20]
    static let operations: [String : (inout Stack<Int>) -> ()] =
    [
        "+" : { $0.push($0.pop() + $0.pop()) },
        "-" : { $0.push($0.pop() - $0.pop()) },
        "*" : { $0.push($0.pop() * $0.pop()) },
        "/" : { $0.push($0.pop() / $0.pop()) }
    ]
}

struct Stack<T>
{
    var values: [T] = []

    var isEmpty: Bool { return values.isEmpty }
    mutating func push(_ n: T)
    {
        values.append(n)
    }

    mutating func pop() -> T
    {
        return values.removeLast()
    }

    func peek() -> T
    {
        return values.last!
    }
}

func shuntingYard(input: [Token]) -> [Token]
{
    var operatorStack = Stack<Token>()
    var output: [Token] = []

    for token in input
    {
        switch token
        {
        case .number:
            output.append(token)
        case .op:
            while !operatorStack.isEmpty && operatorStack.peek().precedence >= token.precedence
            {
                output.append(operatorStack.pop())
            }
            operatorStack.push(token)
        }
    }
    while !operatorStack.isEmpty
    {
        output.append(operatorStack.pop())
    }
    return output
}

let input: [Token] = [ .number(2), .op("+"), .number(2), .op("*"), .number(4)]
let output = shuntingYard(input: input)

print("\(output)")

var dataStack = Stack<Int>()

for token in output
{
    token.operation(&dataStack)
}

print(dataStack.pop())
  func evaluate(_ values: [String]) -> String{
        switch values[1] {
        case "+": return String(Int(values[0])! + Int(values[2])!)
        case "-": return String(Int(values[0])! - Int(values[2])!)
        case "×": return String(Int(values[0])! * Int(values[2])!)
        case "÷": return String(Int(values[0])! / Int(values[2])!)
        default: break;
        }
        return "";
    }

    func oneTime(_  string: inout String, _ strings: [String]) throws{
    if let first = try NSRegularExpression(pattern:  "(\\d+)\\s*(\(strings.map{"\\\($0)"}.joined(separator: "|")))\\s*(\\d+)", options: []).firstMatch(in: string , options: [], range: NSMakeRange(0, string.count)) {
    let tempResult = evaluate((1...3).map{ (string as NSString).substring(with: first.range(at: $0))})
       string.replaceSubrange(  Range(first.range(at: 0), in: string)!  , with: tempResult)
        }
    }

    func recursive(_ string: inout String, _ strings: [String]) throws{
        var count : Int!
        repeat{ count = string.count ; try oneTime(&string, strings)
        } while (count != string.count)
    }

    func final(_ string: inout String, _ strings: [[String]])  throws -> String{
       return try strings.reduce(into: string) { (result, signs) in
            try recursive(&string, signs)
        }}

    var string = "17 - 23 + 10 + 7 ÷ 7"
    try final(&string, [["×","÷"],["+","-"]])
    print("result:" + string)
 let testArray = ["10","+", "5", "*" , "4", "+" , "10", "+", "20", "/", "2"]
     func getRPNArray(calculationArray: [String]) -> [String]{

     let c = calculationArray
     var myRPNArray = [String]()
     var operandArray = [String]()

      for i in 0...c.count - 1 {

          if c[i] != "+" && c[i] != "-" && c[i] != "*" && c[i] != "/" {
              //push number
              let number = c[i]
              myRPNArray.append(number)

          } else  {
              //if this is the first operand put it on the opStack
              if operandArray.count == 0 {
                  let firstOperand = c[i]
                  operandArray.append(firstOperand)
              } else {

                  if  c[i] == "+" || c[i] == "-" {

                          operandArray.reverse()
                          myRPNArray.append(contentsOf: operandArray)
                          operandArray = []

                          let uniqOperand = c[i]
                          operandArray.append(uniqOperand)



                  } else if c[i] == "*" || c[i] == "/" {

                    let strongOperand = c[i]

                    //If I want my mult./div. from right(eg because of parenthesis) the line below is all I need
                    //--------------------------------
                    //      operandArray.append(strongOperand)
                   //----------------------------------

                    //If I want my mult./div. from left
                    let lastOperand = operandArray[operandArray.count - 1]

                    if lastOperand == "+" || lastOperand == "-" {
                        operandArray.append(strongOperand)
                    } else {
                        myRPNArray.append(lastOperand)
                        operandArray.removeLast()
                        operandArray.append(strongOperand)

                    }
                  }
              }
          }

      }

    //when I have no more numbers I append the reversed operant array
      operandArray.reverse()
      myRPNArray.append(contentsOf: operandArray)
      operandArray = []

      print("RPN: \(myRPNArray)")
    return myRPNArray
}
  func getResultFromRPNarray(myArray: [String]) -> Double {
    var a = [String]()
    a = myArray
     print("a: \(a)")
    var result = Double()
    let n = a.count



    for i in 0...n - 1 {
        if n < 2 {
            result = Double(a[0])!
        } else {
            if a[i] == "p" {
             //Do nothing else. Calculations are over and the result is in your hands!!!
            } else {
                if a[i] == "+" {

                   result = Double(a[i-2])! + Double(a[i-1])!
                    a.insert(String(result), at: i-2)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.insert("p", at: 0)
                    a.insert("p", at: 0)

                } else if a[i] == "-" {
                   result = Double(a[i-2])! - Double(a[i-1])!
                    a.insert(String(result), at: i-2)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.insert("p", at: 0)
                    a.insert("p", at: 0)

                } else if a[i] == "*" {
                   result = Double(a[i-2])! * Double(a[i-1])!
                    a.insert(String(result), at: i-2)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.insert("p", at: 0)
                    a.insert("p", at: 0)

                } else if a[i] == "/" {
                   result = Double(a[i-2])! / Double(a[i-1])!
                    a.insert(String(result), at: i-2)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.remove(at: i - 1)
                    a.insert("p", at: 0)
                    a.insert("p", at: 0)
                } else {
                    // it is a number so do nothing and go the next one
                }


            }//no over yet
        }//n>2
    }//iterating
    return result
}//Func