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