Was ist der effizienteste Weg, um zwischen 0und umzuschalten 1?
Was ist der effizienteste Weg, um zwischen 0und umzuschalten 1?
Antworten:
Wenn die Werte boolesch sind, besteht der schnellste Ansatz darin, den Operator not zu verwenden :
>>> x = True
>>> x = not x # toggle
>>> x
False
>>> x = not x # toggle
>>> x
True
>>> x = not x # toggle
>>> x
False
Wenn die Werte numerisch sind, ist die Subtraktion von der Summe eine einfache und schnelle Möglichkeit, Werte umzuschalten:
>>> 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
Wenn der Wert zwischen 0 und 1 wechselt , können Sie ein bitweises Exklusiv-Oder verwenden :
>>> x = 1
>>> x ^= 1
>>> x
0
>>> x ^= 1
>>> x
1
Die Technik verallgemeinert sich auf ein beliebiges Paar von ganzen Zahlen. Der xor-by-one-Schritt wird durch eine xor-by-vorberechnete Konstante ersetzt:
>>> 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
(Diese Idee wurde von Nick Coghlan eingereicht und später von @zxxc verallgemeinert.)
Wenn die Werte hashbar sind, können Sie ein Wörterbuch verwenden:
>>> 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'
Der langsamste Weg ist die Verwendung eines bedingten Ausdrucks :
>>> 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]
Wenn Sie mehr als zwei Werte haben, bietet die Funktion itertools.cycle () eine generische schnelle Möglichkeit, zwischen aufeinanderfolgenden Werten umzuschalten :
>>> import itertools
>>> toggle = itertools.cycle(['red', 'green', 'blue']).next
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'
Beachten Sie, dass in Python 3 die next()Methode in geändert wurde __next__(), sodass die erste Zeile jetzt als geschrieben wirdtoggle = itertools.cycle(['red', 'green', 'blue']).__next__
.next()durch eine globale next()Funktion ersetzt. Das obige Beispiel wäre:toggle = itertools.cycle(...); next(toggle)
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
aund bVerwendung umzuschalten x = x ^ (a ^ b).
int(not 0)und int(not 1)... hrmmm
Ich benutze immer:
p^=True
Wenn p ein Boolescher Wert ist, wird zwischen true und false umgeschaltet.
pmuss nicht zweimal referenziert werden, damit diese Methode funktioniert !! Idee, wenn Sie einen Wert mit einer langen langen Referenz umschalten.
^=ist bitweise xor Zuordnung
Hier ist ein anderer nicht intuitiver Weg. Das Schöne ist, dass Sie über mehrere Werte fahren können und nicht nur über zwei [0,1]
Für zwei Werte (Umschalten)
>>> x=[1,0]
>>> toggle=x[toggle]
Für mehrere Werte (sagen wir 4)
>>> x=[1,2,3,0]
>>> toggle=x[toggle]
Ich hatte nicht erwartet, dass diese Lösung auch fast die schnellste sein würde
>>> 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
Der notOperator negiert Ihre Variable (konvertiert sie in einen Booleschen Wert, falls dies noch nicht geschehen ist). Sie können wahrscheinlich verwenden 1und 0austauschbar mit Trueund False, so ist es einfach zu negieren:
toggle = not toggle
Wenn Sie jedoch zwei beliebige Werte verwenden, verwenden Sie eine Inline if:
toggle = 'a' if toggle == 'b' else 'b'
toggle = 0 if toggle else 1ist kürzer und allgemeiner
ifum zwischen zwei beliebigen Variablen umzuschalten, nicht nur 1und 0.
Tun Sie dies nur zwischen 1 und 0
1-x
x kann 1 oder 0 annehmen
Trueund Falseeigentlich ganze Zahlen sind, wenn auch solche mit einer überraschend ausführlichen __str__()Methode, xkönnen auch Trueoder Falsehier sein. Sie erhalten jedoch 1 oder 0 zurück.
Trigonometrischer Ansatz , nur weil sinund cosFunktionen cool sind.
>>> 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
Überraschenderweise erwähnt niemand die gute alte 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
Beachten Sie, dass dies äquivalent zu x = x - 1ist, der Vorteil der Modulo-Technik jedoch darin besteht, dass die Größe der Gruppe oder die Länge des Intervalls größer als nur 2 Elemente sein kann, sodass Sie ein ähnliches Round-Robin-Interleaving-Schema zum Schleifen erhalten.
Nur für 2 kann das Umschalten etwas kürzer sein (mit dem bitweisen Operator):
x = x ^ 1
Eine Möglichkeit zum Umschalten ist die Verwendung der Mehrfachzuweisung
>>> a = 5
>>> b = 3
>>> t = a, b = b, a
>>> t[0]
3
>>> t = a, b = b, a
>>> t[0]
5
Verwenden von 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
Ausnahmebehandler verwenden
>>> 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, ich bin das Schlimmste:
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)
Wie wäre es mit einem imaginären Umschalter, der nicht nur den aktuellen Umschalter, sondern auch einige andere damit verbundene Werte speichert?
toggle = complex.conjugate
Speichern Sie einen beliebigen + oder - Wert links und einen beliebigen Wert ohne Vorzeichen rechts:
>>> x = 2 - 3j
>>> toggle(x)
(2+3j)
Null funktioniert auch:
>>> y = -2 - 0j
>>> toggle(y)
(-2+0j)
Rufen Sie einfach den aktuellen Umschaltwert ab ( Trueund Falsestellen Sie + und - dar), den LHS-Wert (real) oder den RHS-Wert (imaginär):
>>> 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
Tauschen Sie einfach LHS und RHS aus (beachten Sie jedoch, dass das Vorzeichen der beiden Werte nicht wichtig sein darf):
>>> swap = lambda i: i/-1j
>>> swap(2+0j)
2j
>>> swap(3+2j)
(2+3j)
Tauschen Sie einfach LHS und RHS aus und schalten Sie gleichzeitig um:
>>> swaggle = lambda i: i/1j
>>> swaggle(2+0j)
-2j
>>> swaggle(3+2j)
(2-3j)
Schutz vor Fehlern:
>>> toggle(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'conjugate' requires a 'complex' object but received a 'int'
Führen Sie Änderungen an LHS und RHS durch:
>>> x += 1+2j
>>> x
(3+5j)
... aber seien Sie vorsichtig beim Manipulieren der RHS:
>>> z = 1-1j
>>> z += 2j
>>> z
(1+1j) # whoops! toggled it!
Die Variablen a und b können JEDE zwei Werte sein, wie 0 und 1 oder 117 und 711 oder "Köpfe" und "Schwänze". Es wird keine Mathematik verwendet, nur ein schneller Austausch der Werte jedes Mal, wenn ein Umschalten gewünscht wird.
a = True
b = False
a,b = b,a # a is now False
a,b = b,a # a is now True
Lassen Sie uns ein paar Frame-Hacking machen. Schalten Sie eine Variable nach Namen um. Hinweis: Dies funktioniert möglicherweise nicht mit jeder Python-Laufzeit.
Angenommen, Sie haben eine 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
Wenn Sie es mit einer ganzzahligen Variablen zu tun haben, können Sie 1 erhöhen und Ihre Menge auf 0 und 1 (mod) beschränken.
X = 0 # or X = 1
X = (X + 1)%2
Das Umschalten zwischen -1 und +1 kann durch Inline-Multiplikation erfolgen. wird zur Berechnung von pi nach 'Leibniz'-Art (oder ähnlich) verwendet:
sign = 1
result = 0
for i in range(100000):
result += 1 / (2*i + 1) * sign
sign *= -1
print("pi (estimate): ", result*4)
Sie können die indexvon lists verwenden.
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 : Keine zusätzlichen Bibliotheken, self.explanatory Code und arbeitet mit beliebigen Datentypen.
Nachteile : nicht doppelt speichern.
toggleValues(["one","two","duped", "three", "duped", "four"], "duped")
wird immer wiederkommen"three"