Jak zmienić wartość w Pythonie

128

Jaki jest najskuteczniejszy sposób przełączania się między 0i 1?

codeforester
źródło
podczas gdy to pytanie dotyczy najbardziej efektywnego przełączania wartości w sposób binarny, niektóre odpowiedzi wyjaśniają przechodzenie między (dowolnymi) wartościami, np. stackoverflow.com/a/61041907/537865
szalony

Odpowiedzi:

273

Rozwiązanie wykorzystujące NOT

Jeśli wartości są logiczne, najszybszym podejściem jest użycie operatora not :

>>> x = True
>>> x = not x        # toggle
>>> x
False
>>> x = not x        # toggle
>>> x
True
>>> x = not x        # toggle
>>> x
False

Rozwiązanie za pomocą odejmowania

Jeśli wartości są liczbowe, odejmowanie od sumy jest prostym i szybkim sposobem przełączania wartości:

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

Rozwiązanie wykorzystujące XOR

Jeśli wartość przełącza się między 0 a 1 , możesz użyć bitowego wyłącznika lub :

>>> x = 1
>>> x ^= 1
>>> x
0
>>> x ^= 1
>>> x
1

Technika uogólnia się na dowolną parę liczb całkowitych. Xor-by-one step jest zastępowany przez xor-by-precomputed-fixed:

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

(Pomysł został zgłoszony przez Nicka Coghlana, a później uogólniony przez @zxxc).

Rozwiązanie za pomocą słownika

Jeśli wartości są hashable, możesz użyć słownika:

>>> 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'

Rozwiązanie wykorzystujące wyrażenie warunkowe

Najwolniejszym sposobem jest użycie wyrażenia warunkowego :

>>> 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]

Rozwiązanie wykorzystujące itertools

Jeśli masz więcej niż dwie wartości, funkcja itertools.cycle () zapewnia ogólny, szybki sposób przełączania między kolejnymi wartościami:

>>> import itertools
>>> toggle = itertools.cycle(['red', 'green', 'blue']).next
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'
>>> toggle()
'red'
>>> toggle()
'green'
>>> toggle()
'blue'

Zauważ, że w Pythonie 3 next()metoda została zmieniona na __next__(), więc pierwsza linia byłaby teraz zapisana jakotoggle = itertools.cycle(['red', 'green', 'blue']).__next__

Raymond Hettinger
źródło
Ostatni przykład wydaje się tak sprytny i intuicyjny, ale nie działa w Pythonie 3+ po usunięciu .next (). Czy istnieje sposób, aby działał podobnie w późniejszej wersji Pythona?
labarna
2
@labarna W Pythonie 3 .next()zastąpiono funkcję globalną next(). Powyższy przykład to:toggle = itertools.cycle(...); next(toggle)
elpres
2
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
Maximilian
7
Przykład XOR można uogólnić, aby przełączać między wartościami ai bużywać x = x ^ (a ^ b).
zxxc
int(not 0)i int(not 1)... hrmmm
jhrr
33

Zawsze używam:

p^=True

Jeśli p jest wartością logiczną, przełącza się między prawdą a fałszem.

renger
źródło
1
Idealny! pnie trzeba odwoływać się dwa razy, aby ta metoda działała !! Pomysł, jeśli przełączasz wartość z długą długą referencją.
ThorSummoner
1
jak nazywa się ten operator?
mix3d
4
To jest operator XOR.
bastelflp
1
@ mix3d Dokładnie jest to „wyłączne bitowo lub” (w przeciwieństwie do „wyłączne logiczne” lub) - wiki.python.org/moin/BitwiseOperators . Logiczny XOR nie ma ogólnie określonego operatora w Pythonie, ale można go znaleźć w niektórych specjalnych przypadkach, takich jak moduł dziesiętny.
Taylor Edmiston
@ mix3d ^=to bitowe przypisanie xor
wjandrea
23

Oto inny nieintuicyjny sposób. Piękno polega na tym, że możesz zmieniać wiele wartości, a nie tylko dwie [0,1]

Dla dwóch wartości (przełączanie)

>>> x=[1,0]
>>> toggle=x[toggle]

Dla wielu wartości (powiedzmy 4)

>>> x=[1,2,3,0]
>>> toggle=x[toggle]

Nie spodziewałem się, że to rozwiązanie będzie też prawie najszybsze

>>> 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
źródło
1
tak, to jest schweet jak orzech. dzięki wszystkim, fajnie jest patrzeć, jak różni ludzie podchodzą do problemu (i pouczające).
Fajnie, to miniaturowa maszyna stanowa.
kindall
cóż, twój jest najciekawszy, ale nie jest to to, czego osobiście potrzebuję do tego, o co pytałem, więc ok, myślę, że prosta matematyka jest wtedy prawdopodobnie najlepsza dla mnie, czy nie powinno tam być 1-x?
Tak, ale to nie powinno zmieniać prędkości.
Blender
ai, ale to by było złe, prawda? kilka świetnych odpowiedzi tutaj, TAK rządzi!
19

notOperator neguje zmienną (przekształcenie go w logiczną, jeśli nie jest już jeden). Prawdopodobnie możesz używać 1i 0zamiennie z Truei False, więc po prostu zaneguj to:

toggle = not toggle

Ale jeśli używasz dwóch dowolnych wartości, użyj inline if:

toggle = 'a' if toggle == 'b' else 'b'
Mikser
źródło
1
+1, ale toggle = 0 if toggle else 1jest krótszy i bardziej ogólny
luc
Przepraszam, zamienię zmienne, żeby było jaśniej. Używałem inline ifdo przełączania się między dwiema dowolnymi zmiennymi, a nie tylko 1i 0.
Blender
14

Tylko między 1 a 0, zrób to

1-x 

x może przyjąć 1 lub 0

SM
źródło
Ponieważ (w każdym razie w Pythonie 2.x) Truei Falsesą w rzeczywistości liczbami całkowitymi, chociaż te z zaskakująco rozwlekłą __str__()metodą, xmogą również być Truelub Falsetutaj. Otrzymasz jednak 1 lub 0 z powrotem.
kindall
12

Podejście trygonometryczne , tylko dlatego, że funkcje sini cossą fajne.

wprowadź opis obrazu tutaj

>>> 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
źródło
O mój Boże! Ja <3 ty.
Rishabh Agrahari
2
@RishabhAgrahari, tak stary, byłem zwycięzcą wyzwania Raymonda Hettingera ;)
dani herrera
7

Zaskakujące jest, że nikt nie wspomniał starego dobrego podziału 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

Zauważ, że jest to równoważne x = x - 1, ale zaletą techniki modulo jest to, że rozmiar grupy lub długość interwału może być większy niż tylko 2 elementy, dając w ten sposób schemat przeplotu podobnego do okrężnego.

Teraz tylko dla 2, przełączanie może być nieco krótsze (używając operatora bitowego):

x = x ^ 1
Yauhen Yakimovich
źródło
Nie jestem pewien, jak „pythoniczny” jest to (podobna do C) arytmetyka modulo (tj. Czy „pythonic” ma zastosowanie?). Myślę, że to tylko arytmetyka, działa wszędzie tam, gdzie masz binarny.
Yauhen Yakimovich
Oczywiście maszyna skończonych stanów z krotką taką jak x = (1,2,3,0); token = 0; token = x [token] jest niezwykle ekscytujący, ponieważ może być nawet bardziej ogólny niż tylko operacja grupowa.
Yauhen Yakimovich
7

jednym ze sposobów przełączania jest użycie przypisania wielokrotnego

>>> a = 5
>>> b = 3

>>> t = a, b = b, a
>>> t[0]
3

>>> t = a, b = b, a
>>> t[0]
5

Korzystanie z 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
źródło
4

Najłatwiejszym sposobem przełączania się między 1 a 0 jest odjęcie od 1.

def toggle(value):
    return 1 - value
Królik
źródło
4

Korzystanie z obsługi wyjątków

>>> 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, jestem najgorszy:

wprowadź opis obrazu tutaj

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
źródło
3

A co z wyimaginowanym przełącznikiem, który przechowuje nie tylko bieżący przełącznik, ale kilka innych powiązanych z nim wartości?

toggle = complex.conjugate

Przechowuj dowolną wartość + lub - po lewej stronie i każdą wartość bez znaku po prawej:

>>> x = 2 - 3j
>>> toggle(x)
(2+3j)

Zero też działa:

>>> y = -2 - 0j
>>> toggle(y)
(-2+0j)

Łatwo pobierz bieżącą wartość przełączania ( Truei Falsereprezentuj + i -), wartość LHS (rzeczywistą) lub RHS (urojoną):

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

Łatwo zamień LHS i RHS (ale pamiętaj, że znak obu wartości nie może być ważny):

>>> swap = lambda i: i/-1j
>>> swap(2+0j)
2j
>>> swap(3+2j)
(2+3j)

Łatwo zamień LHS i RHS, a także przełączaj w tym samym czasie:

>>> swaggle = lambda i: i/1j
>>> swaggle(2+0j)
-2j
>>> swaggle(3+2j)
(2-3j)

Ochrona przed błędami:

>>> toggle(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: descriptor 'conjugate' requires a 'complex' object but received a 'int'

Wykonaj zmiany w LHS i RHS:

>>> x += 1+2j
>>> x
(3+5j)

... ale zachowaj ostrożność przy manipulowaniu RHS:

>>> z = 1-1j
>>> z += 2j
>>> z
(1+1j) # whoops! toggled it!
Rick wspiera Monikę
źródło
2

Zmienne a i b mogą mieć DOWOLNE dwie wartości, takie jak 0 i 1 lub 117 i 711 lub „orła” i „reszka”. Nie używa się matematyki, tylko szybka zamiana wartości za każdym razem, gdy wymagane jest przełączenie.

a = True   
b = False   

a,b = b,a   # a is now False
a,b = b,a   # a is now True
user2948775
źródło
1

Używam funkcji abs, bardzo przydatnej na pętlach

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

x będzie równe 0.

Proteo5
źródło
0

Zróbmy hakowanie ramek. Przełącz zmienną według nazwy. Uwaga: to może nie działać w każdym środowisku wykonawczym Pythona.

Powiedzmy, że masz zmienną „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
źródło
0

Jeśli masz do czynienia ze zmienną całkowitą, możesz zwiększyć 1 i ograniczyć swój zestaw do 0 i 1 (mod)

X = 0  # or X = 1
X = (X + 1)%2
Italo Nesi
źródło
0

Przełączanie między -1 a +1 można uzyskać przez mnożenie w wierszu; stosowany do obliczania liczby pi metodą „Leibniza” (lub podobną):

sign = 1
result = 0
for i in range(100000):
    result += 1 / (2*i + 1) * sign
    sign *= -1
print("pi (estimate): ", result*4)
John Bograd
źródło
0

Możesz skorzystać indexz 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"

Zalety : brak dodatkowych bibliotek, samowyjaśnienia kodu i praca z dowolnymi typami danych.

Wady : nie zapisuj duplikatów. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") zawsze wróci"three"

szalony
źródło