What is the most efficient way to toggle between 0 and 1?
17 Answers
Solution using NOT
If the values are boolean, the fastest approach is to use the not operator:
>>> x = True >>> x = not x # toggle >>> x False >>> x = not x # toggle >>> x True >>> x = not x # toggle >>> x False Solution using subtraction
If the values are numerical, then subtraction from the total is a simple and fast way to toggle values:
>>> A = 5 >>> B = 3 >>> total = A + B >>> x = A >>> x = total - x # toggle >>> x 3 >>> x = total - x # toggle >>> x 5 >>> x = total - x # toggle >>> x 3 Solution using XOR
If the value toggles between 0 and 1, you can use a bitwise exclusive-or:
>>> x = 1 >>> x ^= 1 >>> x 0 >>> x ^= 1 >>> x 1 The technique generalizes to any pair of integers. The xor-by-one step is replaced with a xor-by-precomputed-constant:
>>> A = 205 >>> B = -117 >>> t = A ^ B # precomputed toggle constant >>> x = A >>> x ^= t # toggle >>> x -117 >>> x ^= t # toggle >>> x 205 >>> x ^= t # toggle >>> x -117 (This idea was submitted by Nick Coghlan and later generalized by @zxxc.)
Solution using a dictionary
If the values are hashable, you can use a dictionary:
>>> A = 'xyz' >>> B = 'pdq' >>> d = {A:B, B:A} >>> x = A >>> x = d[x] # toggle >>> x 'pdq' >>> x = d[x] # toggle >>> x 'xyz' >>> x = d[x] # toggle >>> x 'pdq' Solution using a conditional expression
The slowest way is to use a conditional expression:
>>> A = [1,2,3] >>> B = [4,5,6] >>> x = A >>> x = B if x == A else A >>> x [4, 5, 6] >>> x = B if x == A else A >>> x [1, 2, 3] >>> x = B if x == A else A >>> x [4, 5, 6] Solution using itertools
If you have more than two values, the itertools.cycle() function provides a generic fast way to toggle between successive values:
>>> import itertools >>> toggle = itertools.cycle(['red', 'green', 'blue']).next >>> toggle() 'red' >>> toggle() 'green' >>> toggle() 'blue' >>> toggle() 'red' >>> toggle() 'green' >>> toggle() 'blue' Note that in Python 3 the next() method was changed to __next__(), so the first line would be now written as toggle = itertools.cycle(['red', 'green', 'blue']).__next__
I always use:
p^=True If p is a boolean, this switches between true and false.
6Here is another non intuitive way. The beauty is you can cycle over multiple values and not just two [0,1]
For Two values (toggling)
>>> x=[1,0] >>> toggle=x[toggle] For Multiple Values (say 4)
>>> x=[1,2,3,0] >>> toggle=x[toggle] I didn't expect this solution to be almost the fastest too
>>> stmt1=""" toggle=0 for i in xrange(0,100): toggle = 1 if toggle == 0 else 0 """ >>> stmt2=""" x=[1,0] toggle=0 for i in xrange(0,100): toggle=x[toggle] """ >>> t1=timeit.Timer(stmt=stmt1) >>> t2=timeit.Timer(stmt=stmt2) >>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=100000)/100000) 7.07 usec/pass >>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000) 6.19 usec/pass stmt3=""" toggle = False for i in xrange(0,100): toggle = (not toggle) & 1 """ >>> t3=timeit.Timer(stmt=stmt3) >>> print "%.2f usec/pass" % (1000000 * t3.timeit(number=100000)/100000) 9.84 usec/pass >>> stmt4=""" x=0 for i in xrange(0,100): x=x-1 """ >>> t4=timeit.Timer(stmt=stmt4) >>> print "%.2f usec/pass" % (1000000 * t4.timeit(number=100000)/100000) 6.32 usec/pass 6The not operator negates your variable (converting it into a boolean if it isn't already one). You can probably use 1 and 0 interchangeably with True and False, so just negate it:
toggle = not toggle But if you are using two arbitrary values, use an inline if:
toggle = 'a' if toggle == 'b' else 'b' 2Just between 1 and 0, do this
1-x x can take 1 or 0
1Trigonometric approach, just because sin and cos functions are cool.
>>> import math >>> def generator01(): ... n=0 ... while True: ... yield abs( int( math.cos( n * 0.5 * math.pi ) ) ) ... n+=1 ... >>> g=generator01() >>> g.next() 1 >>> g.next() 0 >>> g.next() 1 >>> g.next() 0 0Surprisingly nobody mention good old division modulo 2:
In : x = (x + 1) % 2 ; x Out: 1 In : x = (x + 1) % 2 ; x Out: 0 In : x = (x + 1) % 2 ; x Out: 1 In : x = (x + 1) % 2 ; x Out: 0 Note that it is equivalent to x = x - 1, but the advantage of modulo technique is that the size of the group or length of the interval can be bigger then just 2 elements, thus giving you a similar to round-robin interleaving scheme to loop over.
Now just for 2, toggling can be a bit shorter (using bit-wise operator):
x = x ^ 1 2one way to toggle is by using Multiple assignment
>>> a = 5 >>> b = 3 >>> t = a, b = b, a >>> t[0] 3 >>> t = a, b = b, a >>> t[0] 5 Using itertools:
In [12]: foo = itertools.cycle([1, 2, 3]) In [13]: next(foo) Out[13]: 1 In [14]: next(foo) Out[14]: 2 In [15]: next(foo) Out[15]: 3 In [16]: next(foo) Out[16]: 1 In [17]: next(foo) Out[17]: 2 0The easiest way to toggle between 1 and 0 is to subtract from 1.
def toggle(value): return 1 - value Using exception handler
>>> def toogle(x): ... try: ... return x/x-x/x ... except ZeroDivisionError: ... return 1 ... >>> x=0 >>> x=toogle(x) >>> x 1 >>> x=toogle(x) >>> x 0 >>> x=toogle(x) >>> x 1 >>> x=toogle(x) >>> x 0 Ok, I'm the worst:
import math import sys d={1:0,0:1} l=[1,0] def exception_approach(x): try: return x/x-x/x except ZeroDivisionError: return 1 def cosinus_approach(x): return abs( int( math.cos( x * 0.5 * math.pi ) ) ) def module_approach(x): return (x + 1) % 2 def subs_approach(x): return x - 1 def if_approach(x): return 0 if x == 1 else 1 def list_approach(x): global l return l[x] def dict_approach(x): global d return d[x] def xor_approach(x): return x^1 def not_approach(x): b=bool(x) p=not b return int(p) funcs=[ exception_approach, cosinus_approach, dict_approach, module_approach, subs_approach, if_approach, list_approach, xor_approach, not_approach ] f=funcs[int(sys.argv[1])] print "\n\n\n", f.func_name x=0 for _ in range(0,100000000): x=f(x) 0How about an imaginary toggle that stores not only the current toggle, but a couple other values associated with it?
toggle = complex.conjugate Store any + or - value on the left, and any unsigned value on the right:
>>> x = 2 - 3j >>> toggle(x) (2+3j) Zero works, too:
>>> y = -2 - 0j >>> toggle(y) (-2+0j) Easily retrieve the current toggle value (True and False represent + and -), LHS (real) value, or RHS (imaginary) value:
>>> import math >>> curr = lambda i: math.atan2(i.imag, -abs(i.imag)) > 0 >>> lhs = lambda i: i.real >>> rhs = lambda i: abs(i.imag) >>> x = toggle(x) >>> curr(x) True >>> lhs(x) 2.0 >>> rhs(x) 3.0 Easily swap LHS and RHS (but note that the sign of the both values must not be important):
>>> swap = lambda i: i/-1j >>> swap(2+0j) 2j >>> swap(3+2j) (2+3j) Easily swap LHS and RHS and also toggle at the same time:
>>> swaggle = lambda i: i/1j >>> swaggle(2+0j) -2j >>> swaggle(3+2j) (2-3j) Guards against errors:
>>> toggle(1) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: descriptor 'conjugate' requires a 'complex' object but received a 'int' Perform changes to LHS and RHS:
>>> x += 1+2j >>> x (3+5j) ...but be careful manipulating the RHS:
>>> z = 1-1j >>> z += 2j >>> z (1+1j) # whoops! toggled it! Variables a and b can be ANY two values, like 0 and 1, or 117 and 711, or "heads" and "tails". No math is used, just a quick swap of the values each time a toggle is desired.
a = True b = False a,b = b,a # a is now False a,b = b,a # a is now True I use abs function, very useful on loops
x = 1 for y in range(0, 3): x = abs(x - 1) x will be 0.
1Let's do some frame hacking. Toggle a variable by name. Note: This may not work with every Python runtime.
Say you have a variable "x"
>>> import inspect >>> def toggle(var_name): >>> frame = inspect.currentframe().f_back >>> vars = frame.f_locals >>> vars[var_name] = 0 if vars[var_name] == 1 else 1 >>> x = 0 >>> toggle('x') >>> x 1 >>> toggle('x') >>> x 0 If you are dealing with an integer variable, you can increment 1 and limit your set to 0 and 1 (mod)
X = 0 # or X = 1 X = (X + 1)%2 Switching between -1 and +1 can be obtained by inline multiplication; used for calculation of pi the 'Leibniz' way (or similar):
sign = 1 result = 0 for i in range(100000): result += 1 / (2*i + 1) * sign sign *= -1 print("pi (estimate): ", result*4) You can make use of the index of lists.
def toggleValues(values, currentValue): return values[(values.index(currentValue) + 1) % len(values)] > toggleValues( [0,1] , 1 ) > 0 > toggleValues( ["one","two","three"] , "one" ) > "two" > toggleValues( ["one","two","three"] , "three") > "one" Pros: No additional libraries, self.explanatory code and working with arbitrary data types.
Cons: not duplicate-save. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") will always return "three"
