input_string = '''Simon asks / -725
Simon says / 2
Simon says * 2
Simon says * 457
Mary demands + -204
Mary + -414
Simon says - -147
Mary - 823
Mary shouts * -519
Mary demands / -202
Simon says + -974
demands + -404'''
The solution will be built piece by piece, each cell adding something until the solution is complete.
for line in input_string.split('\n'):
print(line)
Simon asks / -725 Simon says / 2 Simon says * 2 Simon says * 457 Mary demands + -204 Mary + -414 Simon says - -147 Mary - 823 Mary shouts * -519 Mary demands / -202 Simon says + -974 demands + -404
for line in input_string.split('\n'):
if line.startswith('Simon says'):
print(line)
Simon says / 2 Simon says * 2 Simon says * 457 Simon says - -147 Simon says + -974
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
print(operator, operand)
/ 2 * 2 * 457 - -147 + -974
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
if operator == '+':
print("add ", operand)
elif operator == '-':
print("substract", operand)
elif operator == '*':
print("multiply", operand)
elif operator == '/':
print('divide', operand)
divide 2 multiply 2 multiply 457 substract -147 add -974
n = 1
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
if operator == '+':
n += operand
elif operator == '-':
n -= operand
elif operator == '*':
n *= operand
elif operator == '/':
n /= operand
n
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Input In [9], in <cell line: 2>() 10 n *= operand 11 elif operator == '/': ---> 12 n /= operand 13 n TypeError: unsupported operand type(s) for /=: 'int' and 'str'
n = 1
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
operand = int(operand)
if operator == '+':
n += operand
elif operator == '-':
n -= operand
elif operator == '*':
n *= operand
elif operator == '/':
n /= operand
n
-370.0
Notice how I didn't catch the fact that I forgot to convert the operant to an int until very late in the process. Python told me I made a mistake and I corrected it.
An 'if forest' is cumbersome to read. One can use a dictionary of functions instead, either using the actual function names for the binary operators -*/+
, or by redefining them, or by using lambdas, which are shorter to write.
operations = {
'*': float.__mul__,
'-': float.__sub__,
'+': float.__add__,
'/': float.__truediv__,
}
n = 1. # Notice how we must start with a float
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
operand = int(operand)
n = operations[operator](n, operand)
n
-370.0
def multiply(a, b):
return a*b
def divide(a, b):
return a/b
def add(a, b):
return a+b
def substract(a,b):
return a-b
operations = {
'*': multiply,
'-': substract,
'+': add,
'/': divide,
}
n = 1
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
operand = int(operand)
n = operations[operator](n, operand)
n
-370.0
operations = {
'*': lambda a,b: a*b,
'-': lambda a, b: a-b,
'+': lambda a, b: a+b,
'/': lambda a, b: a/b,
}
n = 1
for line in input_string.split('\n'):
if line.startswith('Simon says'):
operator, operand = line.split()[-2:]
operand = int(operand)
n = operations[operator](n, operand)
n
-370.0
The eval
function can eat text that is a valid python expression, and return value of this expression.
n = 1
for line in input_string.split('\n'):
if line.startswith('Simon says'):
transformation_to_apply_to_n = line[10:]
print(f'{n=}, {transformation_to_apply_to_n=}')
n = eval(f'n {transformation_to_apply_to_n}')
n
n=1, transformation_to_apply_to_n=' / 2' n=0.5, transformation_to_apply_to_n=' * 2' n=1.0, transformation_to_apply_to_n=' * 457' n=457.0, transformation_to_apply_to_n=' - -147' n=604.0, transformation_to_apply_to_n=' + -974'
-370.0
The recursive function gets an expression, and a list of (operator and operand) couples.
It wraps in ()
the expression and the first (operator and operand) of the list, and calls itself on this new expression and the rest of the list.
When the list is empty, it just returns the expression.
See how the list comprehension is first built from the inside out, and then the recursive function (with prints inside to ease debugging).
[line for line in input_string.splitlines()]
['Simon asks / -725', 'Simon says / 2', 'Simon says * 2', 'Simon says * 457', 'Mary demands + -204', 'Mary + -414', 'Simon says - -147', 'Mary - 823', 'Mary shouts * -519', 'Mary demands / -202', 'Simon says + -974', 'demands + -404']
[line for line in input_string.splitlines() if line.startswith('Simon says')]
['Simon says / 2', 'Simon says * 2', 'Simon says * 457', 'Simon says - -147', 'Simon says + -974']
[line.split() for line in input_string.splitlines() if line.startswith('Simon says')]
[['Simon', 'says', '/', '2'], ['Simon', 'says', '*', '2'], ['Simon', 'says', '*', '457'], ['Simon', 'says', '-', '-147'], ['Simon', 'says', '+', '-974']]
[line.split()[-2:] for line in input_string.splitlines() if line.startswith('Simon says')]
[['/', '2'], ['*', '2'], ['*', '457'], ['-', '-147'], ['+', '-974']]
def recursively_build_expression(current_expr, opop_list):
'''Add the first operator, operand couple in opop list to the expression, then call itself.
Return the total expression.'''
print(f'{current_expr=}, {opop_list=}')
if len(opop_list) == 0:
return current_expr
operator, operand = opop_list[0]
opop_rest = opop_list[1:]
wrapped_expression = f'({current_expr} {operator} {operand})'
return recursively_build_expression(wrapped_expression, opop_rest)
eval(recursively_build_expression('1',
[line.split()[-2:]
for line in input_string.splitlines()
if line.startswith('Simon says')]))
current_expr='1', opop_list=[['/', '2'], ['*', '2'], ['*', '457'], ['-', '-147'], ['+', '-974']] current_expr='(1 / 2)', opop_list=[['*', '2'], ['*', '457'], ['-', '-147'], ['+', '-974']] current_expr='((1 / 2) * 2)', opop_list=[['*', '457'], ['-', '-147'], ['+', '-974']] current_expr='(((1 / 2) * 2) * 457)', opop_list=[['-', '-147'], ['+', '-974']] current_expr='((((1 / 2) * 2) * 457) - -147)', opop_list=[['+', '-974']] current_expr='(((((1 / 2) * 2) * 457) - -147) + -974)', opop_list=[]
-370.0