Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pythonic way to iterate and/or enumerate with a binary 'switch'

I'm working with a few things at the moment where there will be 2n possible outcomes that I need to iterate over in a binary manner.

I'd like some kind of binary enumeration or similar that I could use to switch on and off operators and/or functions in each iteration.

An example where the sign (or +/- operator) is changing over 23=8 iterations may be:

loop1: + var1 + var2 + var3
loop2: + var1 + var2 - var3
loop3: + var1 - var2 + var3
loop4: + var1 - var2 - var3
loop5: - var1 + var2 + var3
loop6: - var1 + var2 - var3
loop7: - var1 - var2 + var3
loop8: - var1 - var2 - var3

Sort of a binary tree, but as a code structure as opposed to a data structure?

Is there a helpful builtin?

like image 505
Lamar Latrell Avatar asked Jul 01 '26 09:07

Lamar Latrell


2 Answers

Just produce the product of binary flags; if you need to switch 3 different things, generate the product of (False, True) three times:

from itertools import product

for first, second, third in product((False, True), repeat=3):

You can also produce the product of operators; your sample could use operator module functions:

import operator
from itertools import product

unary_op = operator.pos, operator.neg

for ops in product(unary_op, repeat=3):
    result = sum(op(var) for op, var in zip(ops, (var1, var2, var3)))

Demo:

>>> from itertools import product
>>> import operator
>>> var1, var2, var3 = 42, 13, 81
>>> unary_op = operator.pos, operator.neg
>>> for ops in product(unary_op, repeat=3):
...     vars = [op(var) for op, var in zip(ops, (var1, var2, var3))]
...     print('{:=3d} + {:=3d} + {:=3d} = {sum:=4d}'.format(*vars, sum=sum(vars)))
...
 42 +  13 +  81 =  136
 42 +  13 + -81 = - 26
 42 + -13 +  81 =  110
 42 + -13 + -81 = - 52
-42 +  13 +  81 =   52
-42 +  13 + -81 = -110
-42 + -13 +  81 =   26
-42 + -13 + -81 = -136
like image 131
Martijn Pieters Avatar answered Jul 03 '26 23:07

Martijn Pieters


As a Numpythonic approach you can create all products of [1, -1] with length 3, then multiply it with your variables then sum the result. In Numpy you can do it with following two steps:

perm = np.vstack((np.repeat(a, 4), np.tile(np.repeat(a, 2), 2), np.tile(a, 4))).T
(perm * (var1, var2, var3)).sum(axis=1)

Demo:

>>> var1 = 5
>>> var2 = 7
>>> var3 = 2
>>> a = np.array([ 1, -1])
>>> perm = np.vstack((np.repeat(a, 4), np.tile(np.repeat(a, 2), 2), np.tile(a, 4))).T
>>> 
>>> perm * (var1, var2, var3)
array([[ 5,  7,  2],
       [ 5,  7, -2],
       [ 5, -7,  2],
       [ 5, -7, -2],
       [-5,  7,  2],
       [-5,  7, -2],
       [-5, -7,  2],
       [-5, -7, -2]])
>>> 

>>> (perm * (var1, var2, var3)).sum(axis=1)
array([ 14,  10,   0,  -4,   4,   0, -10, -14])
like image 35
Mazdak Avatar answered Jul 03 '26 22:07

Mazdak