I have a variable I want to set depending on the values in three booleans. The most straight-forward way is an if statement followed by a series of elifs:
if a a
Another option would be to create a helper function:
def first_true(*args):
true_vals = (arg for arg in args if arg[0])
return next(true_vals)[1]
name = first_true((a and b and c, 'first'),
(a and b and not c, 'second'),
(a and not b and c, 'third'),
(a and not b and not c, 'fourth'),
(not a and b and c, 'fifth'),
(not a and b and not c, 'sixth'),
(not a and not b and c, 'seventh'),
(not a and not b and not c, 'eighth'))
This method assumes that one of the tests passed in will be true. It could also be made lazier with lambdas.
To measure speeds:
from time import clock
a,b,c = True,False,False
A,B,C,D,E,F,G,H = [],[],[],[],[],[],[],[]
for j in xrange(30):
te = clock()
for i in xrange(10000):
name = (a and b and c and 'first' or
a and b and not c and 'second' or
a and not b and c and 'third' or
a and not b and not c and 'fourth' or
not a and b and c and 'fifth' or
not a and b and not c and 'sixth' or
not a and not b and c and 'seventh' or
not a and not b and not c and 'eighth')
A.append(clock()-te)
te = clock()
for i in xrange(10000):
if a and b and c:
name = 'first'
elif a and b and not c:
name = 'second'
elif a and not b and c:
name = 'third'
elif a and not b and not c:
name = 'fourth'
elif not a and b and c:
name = 'fifth'
elif not a and b and not c:
name = 'sixth'
elif not a and not b and c:
name = 'seventh'
elif not a and not b and not c:
name = 'eighth'
B.append(clock()-te)
#=====================================================================================
li = ['eighth', 'seventh', 'sixth', 'fifth', 'fourth', 'third', 'second', 'first']
te = clock()
for i in xrange(10000):
name = li[a*4 + b*2 + c]
C.append(clock()-te)
#=====================================================================================
nth = ['eighth', 'seventh', 'sixth', 'fifth', 'fourth', 'third', 'second', 'first']
te = clock()
for i in xrange(10000):
name = nth[(a and 4 or 0) | (b and 2 or 0) | (c and 1 or 0)]
D.append(clock()-te)
nth = ['eighth', 'seventh', 'sixth', 'fifth', 'fourth', 'third', 'second', 'first']
te = clock()
for i in xrange(10000):
name = nth[(a and 4 or 0) + (b and 2 or 0) + (c and 1 or 0)]
E.append(clock()-te)
#=====================================================================================
values = ['eighth', 'seventh', 'sixth', 'fifth', 'fourth', 'third', 'second', 'first']
te = clock()
for i in xrange(10000):
name = values[( 4 if a else 0 )| ( 2 if b else 0 ) | ( 1 if c else 0 )]
F.append(clock()-te)
values = ['eighth', 'seventh', 'sixth', 'fifth', 'fourth', 'third', 'second', 'first']
te = clock()
for i in xrange(10000):
name = values[( 4 if a else 0 ) + ( 2 if b else 0 ) + ( 1 if c else 0 )]
G.append(clock()-te)
#=====================================================================================
dic = {(True, True, True): "first",
(True, True, False): "second",
(True, False, True): "third",
(True, False, False): "fourth",
(False, True, True): "fifth",
(False, True, False): "sixth",
(False, False, True): "seventh",
(False, False, False): "eighth"}
te = clock()
for i in xrange(10000):
name = dic[a,b,c]
H.append(clock()-te)
print min(A),'\n', min(B),'\n\n', min(C),'\n\n', min(D),'\n',min(E),'\n\n',min(F),'\n', min(G),'\n\n', min(H)
Result
0.0480533140385
0.0450973517584
0.0309056039245
0.0295291720037
0.0286550385594
0.0280122194301
0.0266760160858
0.0249769174574
Since your getting all the combinations, you could create an index based on the values like this:
def value(a,b,c ):
values = ['8th','7th','6th','5th','4th','3rd','2nd','1st']
index = ( 4 if a else 0 ) + ( 2 if b else 0 ) + ( 1 if c else 0 )
return values[index]
if __name__ == "__main__":
print value(True, True, True )
print value(True, True, False )
print value(True, False, True )
print value(True, False, False )
print value(False, True, True )
print value(False, True, False)
print value(False, False, True )
print value(False, False, False)
output:
1st
2nd
3rd
4th
5th
6th
7th
8th
Here is a truth table approach:
lookup = {'000': 'eighth',
'001': 'seventh',
'010': 'sixth',
'011': 'fifth',
'100': 'fourth',
'101': 'third',
'110': 'second',
'111': 'first'}
def key(a, b, c):
return ''.join([str(a),str(b),str(c)])
name = lookup[key(0,1,1)]
You can think of a, b, and c as three bits that when put together form a number between 0 and 7. Then, you can have an array of the values ['first', 'second', ... 'eighth'] and use the bit value as an offset into the array. This would just be two lines of code (one to assemble the bits into a value from 0-7, and one to lookup the value in the array).
Here's the code:
nth = ['eighth', 'seventh', 'sixth', 'fifth', 'fourth', 'third', 'second', 'first']
nth[(a and 4 or 0) | (b and 2 or 0) | (c and 1 or 0)]
if your goal is to avoid writing a lot of "ands" and boolean expressions you can use prime number and only one conditions like this (example for 2 conditions)
cond = (2**cond_1)*(3**cond_2)
so
cond == 1 #means cond_1 and cond_2 are False
cond == 2 #means cond_1 is True and con_2 is False
cond == 3 #means cond_1 is False and con_2 is True
cond == 6 #means con_1 and Con_2 are True
This hack can be used for 3 conditions using 3 primes and so on
Like this...
cond = (2**a)*(3**b)*(5**c)
name = {30:'first', 6: 'second', 10:'third', 2:'fourth',
15:'fifth', 3:'sixth', 5:'seventh', 1:'eighth'}[cond]