Quelle est la manière la plus efficace de basculer entre 0et 1?
Quelle est la manière la plus efficace de basculer entre 0et 1?
Réponses:
Si les valeurs sont booléennes, l'approche la plus rapide consiste à utiliser l' opérateur not :
>>> x = True
>>> x = not x # toggle
>>> x
False
>>> x = not x # toggle
>>> x
True
>>> x = not x # toggle
>>> x
False
Si les valeurs sont numériques, la soustraction du total est un moyen simple et rapide de basculer les valeurs:
>>> 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
Si la valeur bascule entre 0 et 1 , vous pouvez utiliser un ou exclusif au niveau du bit :
>>> x = 1
>>> x ^= 1
>>> x
0
>>> x ^= 1
>>> x
1
La technique se généralise à n'importe quelle paire d'entiers. Le pas xor-par-un est remplacé par une constante xor-par-précalculée:
>>> 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
(Cette idée a été soumise par Nick Coghlan et plus tard généralisée par @zxxc.)
Si les valeurs sont hachables, vous pouvez utiliser un dictionnaire:
>>> 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'
Le moyen le plus lent est d'utiliser une expression conditionnelle :
>>> 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]
Si vous avez plus de deux valeurs, la fonction itertools.cycle () fournit un moyen générique rapide de basculer entre les valeurs successives:
>>> import itertools
>>> toggle = itertools.cycle(['red', 'green', 'blue']).next
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'
Notez que dans Python 3, la next()méthode a été changée en __next__(), donc la première ligne serait maintenant écrite commetoggle = itertools.cycle(['red', 'green', 'blue']).__next__
.next()a été remplacé par une next()fonction globale . L'exemple ci-dessus serait:toggle = itertools.cycle(...); next(toggle)
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
aet l' butilisation x = x ^ (a ^ b).
int(not 0)et int(not 1)... hrmmm
J'utilise toujours:
p^=True
Si p est un booléen, cela bascule entre vrai et faux.
pn'a pas besoin d'être référencé deux fois pour que cette méthode fonctionne !! Idée si vous basculez une valeur avec une longue référence longue.
^=est l' assignation de xor bit à bit
Voici une autre manière non intuitive. La beauté est que vous pouvez parcourir plusieurs valeurs et pas seulement deux [0,1]
Pour deux valeurs (basculement)
>>> x=[1,0]
>>> toggle=x[toggle]
Pour plusieurs valeurs (disons 4)
>>> x=[1,2,3,0]
>>> toggle=x[toggle]
Je ne m'attendais pas à ce que cette solution soit presque la plus rapide aussi
>>> 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
L' notopérateur nie votre variable (en la convertissant en booléen si ce n'est déjà fait). Vous pouvez probablement utiliser 1et de 0manière interchangeable avec Trueet False, alors annulez-le:
toggle = not toggle
Mais si vous utilisez deux valeurs arbitraires, utilisez un inline if:
toggle = 'a' if toggle == 'b' else 'b'
toggle = 0 if toggle else 1est plus court et plus général
ifpour basculer entre deux variables arbitraires , pas seulement 1et 0.
Approche trigonométrique , juste parce que sinet les cosfonctions sont 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
Étonnamment, personne ne mentionne le bon vieux module de division 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
Notez que cela équivaut à x = x - 1, mais l'avantage de la technique modulo est que la taille du groupe ou la longueur de l'intervalle peut être plus grande que 2 éléments, vous donnant ainsi un schéma d'entrelacement similaire au round-robin sur lequel boucler.
Maintenant, juste pour 2, le basculement peut être un peu plus court (en utilisant un opérateur binaire):
x = x ^ 1
une façon de basculer est d'utiliser l'affectation multiple
>>> a = 5
>>> b = 3
>>> t = a, b = b, a
>>> t[0]
3
>>> t = a, b = b, a
>>> t[0]
5
Utilisation d'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
Utilisation du gestionnaire d'exceptions
>>> 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, je suis le pire:
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)
Que diriez-vous d'une bascule imaginaire qui stocke non seulement la bascule actuelle, mais quelques autres valeurs qui lui sont associées?
toggle = complex.conjugate
Stockez toute valeur + ou - à gauche et toute valeur non signée à droite:
>>> x = 2 - 3j
>>> toggle(x)
(2+3j)
Zéro fonctionne aussi:
>>> y = -2 - 0j
>>> toggle(y)
(-2+0j)
Récupérez facilement la valeur de bascule actuelle ( Trueet Falsereprésentent + et -), la valeur LHS (réelle) ou la valeur RHS (imaginaire):
>>> 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
Échangez facilement LHS et RHS (mais notez que le signe des deux valeurs ne doit pas être important):
>>> swap = lambda i: i/-1j
>>> swap(2+0j)
2j
>>> swap(3+2j)
(2+3j)
Échangez facilement LHS et RHS et basculez également en même temps:
>>> swaggle = lambda i: i/1j
>>> swaggle(2+0j)
-2j
>>> swaggle(3+2j)
(2-3j)
Protège contre les erreurs:
>>> toggle(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor 'conjugate' requires a 'complex' object but received a 'int'
Effectuer les modifications de LHS et RHS:
>>> x += 1+2j
>>> x
(3+5j)
... mais soyez prudent en manipulant le RHS:
>>> z = 1-1j
>>> z += 2j
>>> z
(1+1j) # whoops! toggled it!
Les variables a et b peuvent être N'IMPORTE QUELLE deux valeurs, comme 0 et 1, ou 117 et 711, ou "heads" et "tails". Aucun calcul n'est utilisé, juste un échange rapide des valeurs chaque fois qu'une bascule est souhaitée.
a = True
b = False
a,b = b,a # a is now False
a,b = b,a # a is now True
Faisons un peu de piratage de cadre. Basculer une variable par son nom. Remarque: cela peut ne pas fonctionner avec tous les environnements d'exécution Python.
Disons que vous avez une 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
Si vous avez affaire à une variable entière, vous pouvez incrémenter 1 et limiter votre ensemble à 0 et 1 (mod)
X = 0 # or X = 1
X = (X + 1)%2
La commutation entre -1 et +1 peut être obtenue par multiplication en ligne; utilisé pour le calcul de pi la manière 'Leibniz' (ou similaire):
sign = 1
result = 0
for i in range(100000):
result += 1 / (2*i + 1) * sign
sign *= -1
print("pi (estimate): ", result*4)
Vous pouvez utiliser le indexof 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"
Avantages : Aucune bibliothèque supplémentaire, code auto-explicatif et utilisation de types de données arbitraires.
Inconvénients : pas de duplication-sauvegarde.
toggleValues(["one","two","duped", "three", "duped", "four"], "duped")
reviendra toujours"three"