HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Simple calculator which can operate on more than two numbers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cansimplethanoperatemorenumberstwowhichcalculator

Problem

All the calculator programs I have seen so far seem long, complicated and they can only operate on two numbers. Mine is simple, short, and it can operate on as many numbers as you want. Please tell me if there is another way to improve this section of code.

x=[]
amount=int(input("How many numbers?"))
operation=input("(*), (/), (+), (-)")
previous1 = 0
previous2=1
for i in range(amount):
    number=int(input("Number: "))
    x.append(number)
if operation == "+":
    for i in range(amount):
        previous1=x[i]+previous1
elif operation == "*":
    for i in range(amount):
        previous2=x[i]*previous2
elif operation == "-":
    for i in range(amount):
        previous1=x[i]-previous1
elif operation == "/":
    for i in range(amount):
        previous2=x[i]/previous2
if operation == "+" or operation == "-":
    print(previous1)
else:
    print(previous2)

Solution

reduce

Whenever you need to fold an operation across a list, like you're doing, you want to use reduce(). That takes a function, an iterable, and an optional initializer, and performs the operation across all of them. So:

reduce(f, [x, y, z])


is equivalent to:

f(f(x, y), z)


This is precisely what we want. The operator library additionally gives us all the mathematical operators, so we don't have to write them ourselves. So the various operations are:

+: reduce(operator.add, numbers) # or just sum(numbers)
-: reduce(operator.sub, numbers, 0)
*: reduce(operator.mul, numbers)
/: reduce(operator.floordiv, numbers, 1)


Simplifying the logic

We could directly translate the above into a dictionary of operators and a dictionary of initializers:

operators = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '/': operator.floordiv
}

initializers = {
    '-': 0,
    '/': 1
}

result = reduce(operators[operation],
    numbers, 
    initializers.get(operation, None))


This will additionally fix your bug where for subtraction you're really adding.

List Comprehensions

It's more direct to simply initialize your numbers directly:

numbers = [int(input("Number: ")) for _ in range(amount)]


Note that x is not a good name. Prefer more descriptive names.

Division

All of your numbers are ints. Which means that when you divide, you're going to end up with 0 as soon as you have any number that isn't 1. That isn't particularly interesting, so I'd suggest using floating point numbers instead.

Code Snippets

reduce(f, [x, y, z])
f(f(x, y), z)
+: reduce(operator.add, numbers) # or just sum(numbers)
-: reduce(operator.sub, numbers, 0)
*: reduce(operator.mul, numbers)
/: reduce(operator.floordiv, numbers, 1)
operators = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '/': operator.floordiv
}

initializers = {
    '-': 0,
    '/': 1
}

result = reduce(operators[operation],
    numbers, 
    initializers.get(operation, None))
numbers = [int(input("Number: ")) for _ in range(amount)]

Context

StackExchange Code Review Q#113302, answer score: 7

Revisions (0)

No revisions yet.