1

Make a calculator that can solve this in a single line (5+5-4+55-5*6/2)

nums = list(input("Write a mathematical Expression: "))

print(nums)

total = 0

for i in range(len(nums)-1):
  if nums[i] == "+":
    total = total + int(nums[i+1])
  elif nums[i] == "-":
    total = total - int(nums[i+1])
  elif nums[i] == "*":
    total = total * int(nums[i+1])
  elif nums[i] == "/":
    total = total / int(nums[i+1])

print(total)
    

Can someone tell me what the error in my code is? I want to enter the input 5+6-4+3 and it solves it (not pedmas for now)

Barmar
  • 741,623
  • 53
  • 500
  • 612
SaviorTech
  • 66
  • 6
  • Seems like it should start with `total = int(nums[0])`. Note that in addition to not handling order of operations, this also won't handle multi-digit numbers. I'd suggest using `itertools.groupby` to tokenize the input. – Samwise Aug 26 '22 at 00:43
  • You never put the first number into the total. – Barmar Aug 26 '22 at 00:43
  • Since it doesn't handle multi-digit numbers, `+55` in the question won't work. – Barmar Aug 26 '22 at 00:44
  • 1
    Is it cheating to suggest using `eval`? – Chris Aug 26 '22 at 00:46
  • Please include what happens when you enter your mathematical expression? The problem I see with your code (aside for the ```num =list(input(...))``` part which I don't quite get why you did that), your code goes through the expression sequentially. You also need to take into consideration of 'operator precedence'. – ewokx Aug 26 '22 at 00:47
  • I can't do total = int(nums[0]), because lists cannot be turned into integers. This is the error I'm getting – SaviorTech Aug 26 '22 at 00:48
  • Please include the full traceback error. – ewokx Aug 26 '22 at 00:50
  • 2
    Assuming `eval` (the most effortless way of doing it) is not allowed, consider first convert the input string to [Polish Notation](https://www.omnicalculator.com/math/polish-notation), i.e. `-+-+5 5 4 55 /*5 6 2`. – zhugen Aug 26 '22 at 01:03
  • Possibly useful: https://stackoverflow.com/questions/2371436/evaluating-a-mathematical-expression-in-a-string – Chris Aug 26 '22 at 01:04

1 Answers1

0

One way of handling this might be with regular expressions. You can use re.sub with a lambda, and specified to only sub one time, in a while loop to continually replace subexpressions with their results until no operators are found.

This does not respect order of operations.

import re

e = '5+5-4+55-5*6/2'

while re.search(r'[+\-*/]', e):
  e = re.sub(r'(\d+)([*/+\-])(\d+)', 
             lambda x: f"{int(x.groups()[0]) + int(x.groups()[2])}" if (op := x.groups()[1]) == '+' else \
                       f"{int(x.groups()[0]) - int(x.groups()[2])}" if op == '-' else \
                       f"{int(x.groups()[0]) * int(x.groups()[2])}" if op == '*' else \
                       f"{int(x.groups()[0]) / int(x.groups()[2])}", 
             e, 1)

Result is 168.0.

It is possible to modify this slightly to look for only multiplication and vision first, then to look for addition and subtraction.

import re

e = '5+5-4+55-5*6/2'

while re.search(r'[/*]', e):
  e = re.sub(r'(\d+)([/*])(\d+)', 
             lambda x: f"{int(x.groups()[0]) * int(x.groups()[2])}" if x.groups()[1] == '*' else \
                       f"{int(x.groups()[0]) / int(x.groups()[2])}", 
             e, 1)

while re.search(r'[+\-]', e):
  e = re.sub(r'(\d+)([+\-])(\d+)', 
             lambda x: f"{int(x.groups()[0]) + int(x.groups()[2])}" if x.groups()[1] == '+' else \
                       f"{int(x.groups()[0]) - int(x.groups()[2])}", 
             e, 1)

Result: e is now 46.0.

Chris
  • 26,361
  • 5
  • 21
  • 42