So schalten Sie einen Wert in Python um

127

Was ist der effizienteste Weg, um zwischen 0und umzuschalten 1?

Codeforester
quelle
Während in dieser Frage gefragt wird, wie Werte auf binäre Weise am effizientesten umgeschaltet werden
mad

Antworten:

272

Lösung mit NOT

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

Lösung mit Subtraktion

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

Lösung mit XOR

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.)

Lösung mit einem Wörterbuch

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'

Lösung unter Verwendung eines bedingten Ausdrucks

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]

Lösung mit itertools

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__

Raymond Hettinger
quelle
Das letzte Beispiel scheint so schick und intuitiv zu sein, funktioniert aber in Python 3+ nicht, wenn .next () entfernt wird. Gibt es eine Möglichkeit, es in einer späteren Version von Python ähnlich zu machen?
Labarna
2
@labarna In Python 3 wurde das .next()durch eine globale next()Funktion ersetzt. Das obige Beispiel wäre:toggle = itertools.cycle(...); next(toggle)
Elpres
2
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
Maximilian
7
Das XOR-Beispiel kann verallgemeinert werden, um zwischen Werten aund bVerwendung umzuschalten x = x ^ (a ^ b).
zxxc
int(not 0)und int(not 1)... hrmmm
jhrr
33

Ich benutze immer:

p^=True

Wenn p ein Boolescher Wert ist, wird zwischen true und false umgeschaltet.

renger
quelle
1
Perfekt! pmuss nicht zweimal referenziert werden, damit diese Methode funktioniert !! Idee, wenn Sie einen Wert mit einer langen langen Referenz umschalten.
ThorSummoner
1
Wie heißt dieser Operator?
mix3d
4
Dies ist der XOR-Operator.
Bastelflp
1
@ mix3d Genau genommen ist es "bitweise exklusiv oder" (im Gegensatz zu "logisch exklusiv oder") - wiki.python.org/moin/BitwiseOperators . Logisches XOR hat in Python im Allgemeinen keinen bestimmten Operator, aber Sie können ihn in einigen speziellen Fällen wie im Dezimalmodul implementieren .
Taylor Edmiston
@ mix3d ^=ist bitweise xor Zuordnung
wjandrea
23

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
Abhijit
quelle
1
Ja, das ist schweet als Nuss.
Schön, es ist eine Miniatur-Zustandsmaschine.
Kindall
Nun, dein ist das interessanteste, aber es ist nicht das, was ich persönlich für das, was ich gefragt habe, brauche. Also ok, ich denke, das einfache mathematische ist dann wahrscheinlich das beste für mich, sollte das nicht 1-x sein?
Ja, aber das sollte die Geschwindigkeit nicht anders machen.
Blender
ai, aber es würde es falsch machen, nicht wahr? Einige großartige Antworten hier, SO rockt!
19

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'
Mixer
quelle
1
+1 aber toggle = 0 if toggle else 1ist kürzer und allgemeiner
luc
Entschuldigung, ich werde Variablen austauschen, um es klarer zu machen. Ich habe die Inline verwendet, ifum zwischen zwei beliebigen Variablen umzuschalten, nicht nur 1und 0.
Blender
14

Tun Sie dies nur zwischen 1 und 0

1-x 

x kann 1 oder 0 annehmen

MS
quelle
Da (in Python 2.x jedenfalls) 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.
Kindall
12

Trigonometrischer Ansatz , nur weil sinund cosFunktionen cool sind.

Geben Sie hier die Bildbeschreibung ein

>>> 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
dani herrera
quelle
Oh mein Gott! Ich <3 Dich.
Rishabh Agrahari
2
@ RishabhAgrahari, ja Mann, ich war der Herausforderungssieger von Raymond Hettinger ;)
dani herrera
7

Ü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
Yauhen Yakimovich
quelle
Ich bin nicht sicher, wie "pythonisch" diese (C-ähnliche) Modulo-Arithmetik ist (d. H. Ob "pythonisch" gilt?). Ich denke, es ist nur Arithmetik, funktioniert überall, wo Sie Binär haben.
Yauhen Yakimovich
Offensichtlich ist die Finite-State-Maschine mit einem Tupel wie x = (1,2,3,0); token = 0; token = x [token] ist äußerst aufregend, da es noch allgemeiner sein kann als nur eine Gruppenoperation.
Yauhen Yakimovich
7

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
hugo24
quelle
4

Der einfachste Weg, zwischen 1 und 0 umzuschalten, ist das Subtrahieren von 1.

def toggle(value):
    return 1 - value
Häschen
quelle
4

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:

Geben Sie hier die Bildbeschreibung ein

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)
dani herrera
quelle
3

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!
Rick unterstützt Monica
quelle
2

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
user2948775
quelle
1

Ich benutze die abs-Funktion, sehr nützlich bei Loops

x = 1
for y in range(0, 3):
    x = abs(x - 1)

x wird 0 sein.

Proteo5
quelle
0

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
Brantley Harris
quelle
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
Italo Nesi
quelle
0

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)
John Bograd
quelle
0

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"

wütend
quelle