Python'da bir değer nasıl değiştirilir


Yanıtlar:


273

NOT kullanarak çözüm

Değerler boole ise, en hızlı yaklaşım not operatörünü kullanmaktır :

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

Çıkarma kullanarak çözüm

Değerler sayısal ise, toplamdan çıkarma, değerleri değiştirmenin basit ve hızlı bir yoludur:

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

XOR kullanarak çözüm

Değer 0 ile 1 arasında geçiş yapıyorsa, bit düzeyinde dışlayıcı veya :

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

Teknik, herhangi bir tam sayı çiftine genelleştirir. Xor-by-one adımı, önceden hesaplanmış xor-by-sabit ile değiştirilir:

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

(Bu fikir Nick Coghlan tarafından sunuldu ve daha sonra @zxxc tarafından genelleştirildi.)

Sözlük kullanarak çözüm

Değerler karma hale getirilebilirse, bir sözlük kullanabilirsiniz:

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

Koşullu ifade kullanan çözüm

En yavaş yol, koşullu ifade kullanmaktır :

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

Itertools kullanarak çözüm

İkiden fazla değeriniz varsa itertools.cycle () işlevi, ardışık değerler arasında geçiş yapmak için genel ve hızlı bir yol sağlar:

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

Python 3'te next()yöntemin olarak değiştirildiğini __next__(), bu nedenle ilk satırın şimdi şu şekilde yazılacağını unutmayın:toggle = itertools.cycle(['red', 'green', 'blue']).__next__


Son örnek çok şık ve sezgisel görünüyor, ancak Python 3 + 'da .next () kaldırıldığında çalışmıyor. Python'un sonraki sürümlerinde benzer şekilde çalışmasını sağlamanın bir yolu var mı?
labarna

2
@labarna Python 3'te, .next()global bir next()işlevin yerini almıştır . Yukarıdaki örnek şöyle olacaktır:toggle = itertools.cycle(...); next(toggle)
elpres

2
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
Maximilian

7
XOR örneği, değerler arasında geçiş yapmak ave bkullanmak için genelleştirilebilir x = x ^ (a ^ b).
zxxc

int(not 0)ve int(not 1)... hrmmm
jhrr

33

Ben her zaman kullanırım:

p^=True

P bir boole ise, bu doğru ve yanlış arasında geçiş yapar.


1
Mükemmel! pbu yöntemin çalışması için iki kez başvurulmasına gerek yoktur !! Uzun uzun bir referansla bir değer arasında geçiş yapıyorsanız fikir.
ThorSummoner

1
bu operatöre ne denir?
mix3d

4
Bu XOR operatörüdür.
bastelflp

1
@ mix3d Kesinlikle "bit düzeyinde özeldir" veya ("mantıksal özel veya" nin aksine) - wiki.python.org/moin/BitwiseOperators . Mantıksal XOR yok genel olarak Python belirli bir operatöre ancak bunu uygulamaya bulabilirsiniz bazı özel durumlarda ondalık modülünde gibi.
Taylor Edmiston

@ mix3d ^=bit düzeyinde xor ödev olduğunu
wjandrea

23

İşte sezgisel olmayan başka bir yol. Güzel olan, yalnızca iki [0,1] değil birden çok değer arasında geçiş yapabilmenizdir

İki değer için (geçiş)

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

Çoklu Değerler için (4 diyelim)

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

Bu çözümün de neredeyse en hızlı olmasını beklemiyordum

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

1
evet bu bir ceviz olarak schweet. herkese teşekkürler, farklı insanların soruna nasıl yaklaştığına bakmak eğlenceli (ve bilgilendirici.)

Güzel, minyatür bir durum makinesi.
lütfen

Pekala, seninki en ilginç, ama sorduğum şey için kişisel olarak ihtiyacım olan şey bu değil, yani tamam, bence basit matematik olan benim için muhtemelen en iyisi, 1-x orada olması gerekmez mi?

Evet, ama bu hızı hiç farklı kılmaz.
Blender

ai, ama bu yanlış olur, öyle değil mi? burada bazı harika cevaplar, ÇOK harika!

19

notOperatör Değişkeninizi olumsuzlar (zaten biri değilse bir mantıksal dönüştürerek). Sen olabilir muhtemelen kullanmak 1ve 0birbirlerinin yerine sahip Trueve Falsebu yüzden sadece bunu boşa:

toggle = not toggle

Ancak iki rastgele değer kullanıyorsanız, bir satır içi kullanın if:

toggle = 'a' if toggle == 'b' else 'b'

1
+1 ancak toggle = 0 if toggle else 1daha kısa ve daha genel
luc

Üzgünüm, daha net hale getirmek için değişkenleri değiştireceğim. Sadece ve değil, ifiki gelişigüzel değişken arasında geçiş yapmak için inline'ı kullanıyordum . 10
Blender

14

1 ile 0 arasında, bunu yapın

1-x 

x 1 veya 0 alabilir


(Python 2.x'te, her neyse) Trueve Falseaslında tamsayı olduklarından, şaşırtıcı derecede ayrıntılı bir __str__()yönteme sahip olanlar xda olabilir , burada Trueveya Falseburada da olabilir . Yine de 1 veya 0 alacaksın.
kindall

12

Trigonometrik yaklaşım , çünkü sinve cosfonksiyonlar harika.

görüntü açıklamasını buraya girin

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

Aman Tanrım! Ben <3 sen.
Rishabh Agrahari

2
@RishabhAgrahari, evet adam, ben Raymond Hettinger en meydan kazanan );
Dani herrera

7

Şaşırtıcı bir şekilde, kimse eski güzel modulo 2'den bahsetmiyor:

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

Eşdeğeri olduğuna dikkat edin x = x - 1, ancak modulo tekniğinin avantajı, grubun boyutunun veya aralığın uzunluğunun sadece 2 öğeden daha büyük olabilmesidir, böylece size döngü için yuvarlak sıralı serpiştirme şemasına benzer bir verir.

Şimdi sadece 2 için, geçiş biraz daha kısa olabilir (bit bilge operatörü kullanılarak):

x = x ^ 1

Bu (C-benzeri) modülo aritmetiğinin nasıl "pitonik" olduğundan emin değilim (i, e, "pitonik" mi geçerli?). Sanırım bu sadece aritmetik, ikili değerin olduğu her yerde çalışıyor.
Yauhen Yakimovich

Açıktır ki, x = (1,2,3,0) gibi tuple ile sonlu durum makinesi; token = 0; token = x [token], grup işleminden daha genel olabileceği için son derece heyecan vericidir.
Yauhen Yakimovich

7

Geçiş yapmanın bir yolu, Çoklu atama kullanmaktır

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

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

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

Yineleme araçları kullanma:

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

4

1 ile 0 arasında geçiş yapmanın en kolay yolu 1'den çıkarmaktır.

def toggle(value):
    return 1 - value

4

İstisna işleyiciyi kullanma

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

Tamam, ben en kötüsüyüm:

görüntü açıklamasını buraya girin

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)

3

Yalnızca mevcut geçişi değil, aynı zamanda onunla ilişkili birkaç değeri de saklayan hayali bir geçişe ne dersiniz ?

toggle = complex.conjugate

Solda herhangi bir + veya - değerini ve sağda herhangi bir işaretsiz değeri saklayın:

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

Sıfır da işe yarar:

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

Mevcut geçiş değerini ( Trueve False+ ve --'yi temsil eden), LHS (gerçek) değeri veya RHS (sanal) değerini kolayca alın :

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

LHS ve RHS'yi kolayca değiştirin (ancak her iki değerin işaretinin önemli olmaması gerektiğini unutmayın):

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

LHS ve RHS'yi kolayca değiştirin ve aynı zamanda geçiş yapın:

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

Hatalara karşı koruma sağlar:

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

LHS ve RHS'de değişiklik yapın:

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

... ancak RHS'yi kullanırken dikkatli olun:

>>> z = 1-1j
>>> z += 2j
>>> z
(1+1j) # whoops! toggled it!

2

A ve b değişkenleri 0 ve 1 veya 117 ve 711 gibi HERHANGİ iki değer veya "yazı" ve "yazı" olabilir. Hiçbir matematik kullanılmaz, sadece bir geçiş istendiğinde değerlerin hızlı bir şekilde değiştirilmesi yeterlidir.

a = True   
b = False   

a,b = b,a   # a is now False
a,b = b,a   # a is now True

1

Döngülerde çok faydalı olan abs işlevini kullanıyorum

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

x, 0 olacaktır.


0

Biraz çerçeve hackleme yapalım. Bir değişkeni ada göre değiştirin. Not: Bu, her Python çalışma zamanında çalışmayabilir.

Bir değişken "x" e sahip olduğunuzu varsayalım

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

0

Bir tamsayı değişkeni ile uğraşıyorsanız, 1'i artırabilir ve setinizi 0 ve 1 (mod) ile sınırlayabilirsiniz.

X = 0  # or X = 1
X = (X + 1)%2

0

-1 ve +1 arasında geçiş, satır içi çarpma ile elde edilebilir; pi 'Leibniz' yolu (veya benzeri) hesaplamak için kullanılır:

sign = 1
result = 0
for i in range(100000):
    result += 1 / (2*i + 1) * sign
    sign *= -1
print("pi (estimate): ", result*4)

0

Sen yararlanabilirler indexait 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"

Artıları : Ek kitaplık, kendi kendini açıklayan kod yok ve rastgele veri türleriyle çalışma.

Eksileri : çift kaydetme değil. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") her zaman geri dönecek"three"

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.