How do I iterate through arithmetic operators through a static, exclude formula in Python?
I am trying to use itertools to iterate through math operators. Usually array
[1, 2, 3]
using combinations
I can get the results:
1 1,2 1,3 2,3 1,2,3
and etc.
I want to use this on array
from [1, 2, 3]
in such a way that:
1+2+3 1+2-3 1+2/3 1+2*3 1-2+3 1-2-3 1-2/3 1-2*3 ...
arises and gives the results of the equation.
How can i do this?
source to share
The solution generalized to any number of operands and preserves the normal precedence of the operators:
from itertools import product
operands = [1, 2, 3, 4]
operators = [ '+', '*', '-', '//' ] # change '//' to '/' for floating point division
for opers in product(operators, repeat=len(operands)-1):
formula = [ str(operands[0]) ]
for op, operand in zip(opers, operands[1:]):
formula.extend([op, str(operand)])
formula = ' '.join(formula)
print('{} = {}'.format(formula, eval(formula)))
source to share
This is how I approach it:
import itertools
import operator
First, create a list of all possible combinations:
funcs = [operator.add, operator.sub, operator.mul, operator.div]
combos = list(itertools.product(funcs, repeat=2))
>>[(<function operator.add>, <function operator.add>),
(<function operator.add>, <function operator.sub>),
(<function operator.add>, <function operator.mul>),
(<function operator.add>, <function operator.div>),
(<function operator.sub>, <function operator.add>),
(<function operator.sub>, <function operator.sub>),
(<function operator.sub>, <function operator.mul>),
(<function operator.sub>, <function operator.div>),
(<function operator.mul>, <function operator.add>),
(<function operator.mul>, <function operator.sub>),
(<function operator.mul>, <function operator.mul>),
(<function operator.mul>, <function operator.div>),
(<function operator.div>, <function operator.add>),
(<function operator.div>, <function operator.sub>),
(<function operator.div>, <function operator.mul>),
(<function operator.div>, <function operator.div>)]
We will then iterate over this list, solving all possible results:
for fn in combos:
print 'This combo {} yielded this result {}'.format(fn, fn[1](fn[0](*seq[:2]), seq[-1]))
This combo (<built-in function add>, <built-in function add>) yielded this result 6
This combo (<built-in function add>, <built-in function sub>) yielded this result 0
This combo (<built-in function add>, <built-in function mul>) yielded this result 9
This combo (<built-in function add>, <built-in function div>) yielded this result 1
This combo (<built-in function sub>, <built-in function add>) yielded this result 2
This combo (<built-in function sub>, <built-in function sub>) yielded this result -4
This combo (<built-in function sub>, <built-in function mul>) yielded this result -3
This combo (<built-in function sub>, <built-in function div>) yielded this result -1
This combo (<built-in function mul>, <built-in function add>) yielded this result 5
This combo (<built-in function mul>, <built-in function sub>) yielded this result -1
This combo (<built-in function mul>, <built-in function mul>) yielded this result 6
This combo (<built-in function mul>, <built-in function div>) yielded this result 0
This combo (<built-in function div>, <built-in function add>) yielded this result 3
This combo (<built-in function div>, <built-in function sub>) yielded this result -3
This combo (<built-in function div>, <built-in function mul>) yielded this result 0
This combo (<built-in function div>, <built-in function div>) yielded this result 0
Edit: here is what follows the rules of operations
ops = ['+','-','*','/']
combos = list(itertools.product(ops, repeat=2))
for tup in list(itertools.product(combos, [seq])):
print 'These operations {} evaluate to this ---> {}'.format(tup[0],eval(''.join(*zip(seq[0],tup[0][0],seq[1],tup[0][1],seq[-1]))))
These operations ('+', '+') evaluate to this ---> 6
These operations ('+', '-') evaluate to this ---> 0
These operations ('+', '*') evaluate to this ---> 7
These operations ('+', '/') evaluate to this ---> 1
These operations ('-', '+') evaluate to this ---> 2
These operations ('-', '-') evaluate to this ---> -4
These operations ('-', '*') evaluate to this ---> -5
These operations ('-', '/') evaluate to this ---> 1
These operations ('*', '+') evaluate to this ---> 5
These operations ('*', '-') evaluate to this ---> -1
These operations ('*', '*') evaluate to this ---> 6
These operations ('*', '/') evaluate to this ---> 0
These operations ('/', '+') evaluate to this ---> 3
These operations ('/', '-') evaluate to this ---> -3
These operations ('/', '*') evaluate to this ---> 0
These operations ('/', '/') evaluate to this ---> 0
source to share
Not graceful (done on the knee) but works, just to point out my logic. The idea is to shorten the list one by one in the correct order. For example:.
Data: 1 * 2 + 3 * 4
- After step 1 (first * estimated): 2 + 3 * 4
- After step 2 (second * rated): 2 + 12
- After step 3 (+ score): 14
Code:
import operator
import itertools
data = [1.0, 2.0, 3.0, 4.0]
operators_1 = [operator.mul, operator.div] # this operators have priority over that below
operators_2 = [operator.add, operator.sub]
def processOps(formula, data, operators):
res_formula = list(formula)
result = list(data)
for op in formula:
if op not in operators: continue
i = res_formula.index(op)
result = result[:i] + [op(result[i], result[i + 1])] + result[i + 2:]
res_formula.remove(op)
if len(result) == 1:
break
return (res_formula, result)
for f in itertools.product(operators_1 + operators_2, repeat=len(data)-1):
result = list(data)
formula = list(f)
formula, result = processOps(formula, result, operators_1)
formula, result = processOps(formula, result, operators_2)
print f, result
UDP . This updated logic correctly handles cases like (1 * 2) + (3/4).
source to share
Use the appropriate functions in the module operator
and iterate over them in pairs.
import itertools
import operator
ops = [operator.add, operator.sub, operator.mul, operator.div]
for f1, f2 in itertools.product(*ops, repeat=2):
print f1(array[0], f2(array[1], array[2]))
Now, if it array
can be of arbitrary length, it gets a little trickier.
for operations in itertools.product(*ops, repeat=len(array)-1):
result = operations[0](array[0], array[1])
for op, operand in zip(operations[1:], array[2:]):
result = op(result, operand)
print(result)
The structure above avoids the need to know the appropriate identification element for each operation.
If you want to subordinate priority (as seems likely), you need to create an expression and evaluate it with eval
(standard warnings apply).
for ops in itertool.product("+", "-", "*", "/", repeat=len(array)-1):
expr = "%s%s%s" % (array[0], ops[0], array[1])
for op, operand in zip(ops[1:], array[2:]):
expr = "%s%s%s" % (expr, op, operand)
result = eval(expr)
I leave it as an exercise to extend this expression to create parenthesized expressions such as (1+2)*3
in addition to 1+2*3
.
source to share