Cara mengubah nilai dengan Python

128

Apa cara paling efisien untuk beralih antara 0dan 1?

codeforester
sumber
sementara pertanyaan ini menanyakan cara mengubah nilai dengan cara biner paling efisien, beberapa jawaban menjelaskan perputaran melalui nilai (sewenang-wenang), misalnya stackoverflow.com/a/61041907/537865
mad

Jawaban:

273

Solusi menggunakan NOT

Jika nilainya boolean, pendekatan tercepat adalah menggunakan operator not :

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

Solusi menggunakan pengurangan

Jika nilainya berupa numerik, pengurangan dari total adalah cara sederhana dan cepat untuk mengubah nilai:

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

Solusi menggunakan XOR

Jika nilainya berubah antara 0 dan 1 , Anda dapat menggunakan eksklusif bitwise-atau :

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

Teknik ini menggeneralisasi pasangan bilangan bulat apa pun. Langkah xor-oleh-satu diganti dengan konstanta xor-oleh-dihitung-awal:

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

(Ide ini diajukan oleh Nick Coghlan dan kemudian digeneralisasikan oleh @zxxc.)

Solusi menggunakan kamus

Jika nilainya dapat dicirikan, Anda dapat menggunakan kamus:

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

Solusi menggunakan ekspresi kondisional

Cara paling lambat adalah dengan menggunakan ekspresi bersyarat :

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

Solusi menggunakan itertools

Jika Anda memiliki lebih dari dua nilai, fungsi itertools.cycle () menyediakan cara cepat umum untuk beralih di antara nilai-nilai yang berurutan:

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

Perhatikan bahwa dalam Python 3 next()metode diubah menjadi __next__(), jadi baris pertama sekarang akan ditulis sebagaitoggle = itertools.cycle(['red', 'green', 'blue']).__next__

Raymond Hettinger
sumber
Contoh terakhir tampak sangat apik dan intuitif, tetapi tidak berfungsi di Python 3+ dengan penghapusan .next (). Apakah ada cara untuk membuatnya bekerja dengan cara yang sama di versi python?
labarna
2
@labarna Dengan Python 3, .next()telah diganti dengan next()fungsi global . Contoh di atas akan menjadi:toggle = itertools.cycle(...); next(toggle)
elpres
2
toggle = itertools.cycle(['red', 'green', 'blue']) next(toggle)
Maximilian
7
Contoh XOR dapat digeneralisasikan untuk beralih antara nilai adan bpenggunaan x = x ^ (a ^ b).
zxxc
int(not 0)dan int(not 1)...
hrmmm
33

Saya selalu menggunakan:

p^=True

Jika p adalah boolean, ini beralih antara benar dan salah.

renger
sumber
1
Sempurna! ptidak perlu direferensikan dua kali agar metode ini bekerja !! Ide jika Anda mengubah nilai dengan referensi yang panjang.
ThorSummoner
1
apa nama operator ini?
mix3d
4
Ini adalah operator XOR.
bastelflp
1
@ mix3d Tepatnya ini adalah "eksklusif bitwise atau" (berlawanan dengan "eksklusif logis atau") - wiki.python.org/moin/BitwiseOperators . Logical XOR tidak memiliki operator khusus di Python secara umum tetapi Anda dapat menemukannya diimplementasikan dalam beberapa kasus khusus seperti pada modul desimal.
Taylor Edmiston
@ mix3d ^=adalah bitwise xor assigment
wjandrea
23

Berikut cara non-intuitif lainnya. Yang menarik adalah Anda dapat memutar beberapa nilai dan bukan hanya dua [0,1]

Untuk Dua nilai (toggling)

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

Untuk Beberapa Nilai (katakanlah 4)

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

Saya tidak berharap solusi ini menjadi yang tercepat juga

>>> 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
sumber
1
ya itu schweet sebagai kacang. terima kasih semuanya ini menyenangkan melihat bagaimana orang yang berbeda mendekati masalah (dan informatif.)
Bagus, ini mesin miniatur negara.
kindall
Nah, yang satu ini yang paling menarik, tapi itu bukan yang saya butuhkan secara pribadi untuk hal yang saya tanyakan, jadi oke, saya pikir yang sederhana matematika mungkin yang terbaik untuk saya, bukankah itu harus 1-x di sana?
Ya, tapi itu seharusnya tidak membuat kecepatannya berbeda.
Blender
ai, tapi itu akan membuatnya salah kan? beberapa jawaban bagus di sini, SANGAT BAIK!
19

The notOperator meniadakan variabel Anda (mengubahnya menjadi boolean jika tidak sudah satu). Anda mungkin dapat menggunakan 1dan secara 0bergantian dengan Truedan False, jadi negasikan saja:

toggle = not toggle

Tetapi jika Anda menggunakan dua nilai arbitrer, gunakan sebaris if:

toggle = 'a' if toggle == 'b' else 'b'
Blender
sumber
1
+1 tetapi toggle = 0 if toggle else 1lebih pendek dan lebih umum
luc
Maaf, saya akan menukar variabel agar lebih jelas. Saya menggunakan inline ifuntuk beralih antara dua variabel sembarang , bukan hanya 1dan 0.
Blender
14

Hanya antara 1 dan 0, lakukan ini

1-x 

x dapat mengambil 1 atau 0

MS
sumber
Sejak (dalam Python 2.x, bagaimanapun) Truedan Falsesebenarnya bilangan bulat, meskipun dengan __str__()metode verbose yang mengejutkan , xjuga bisa Trueatau di Falsesini. Anda akan mendapatkan kembali 1 atau 0.
kindall
12

Pendekatan trigonometri , hanya karena sindan cosfungsinya keren.

masukkan deskripsi gambar di sini

>>> 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
sumber
Ya Tuhan! Saya <3 Kamu.
Rishabh Agrahari
2
@RishabhAgrahari, ya man, saya adalah pemenang tantangan Raymond Hettinger ;)
dani herrera
7

Anehnya tidak ada yang menyebutkan modulo 2 divisi lama yang bagus:

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

Perhatikan bahwa ini setara dengan x = x - 1, tetapi keuntungan dari teknik modulo adalah bahwa ukuran grup atau panjang interval bisa lebih besar dari hanya 2 elemen, sehingga memberi Anda skema interleaving yang mirip dengan round-robin untuk mengulang.

Sekarang hanya untuk 2 orang, toggling bisa sedikit lebih pendek (menggunakan operator bit-bijaksana):

x = x ^ 1
Yauhen Yakimovich
sumber
Saya tidak yakin bagaimana "pythonic" adalah aritmatika modulo (seperti C) ini (i, e, apakah "pythonic" berlaku?). Saya kira itu hanya aritmatika, bekerja di tempat lain di mana Anda memiliki biner.
Yauhen Yakimovich
Jelas mesin negara-hingga dengan tupel seperti x = (1,2,3,0); token = 0; token = x [token] sangat menarik, karena bisa lebih umum daripada hanya operasi grup.
Yauhen Yakimovich
7

salah satu cara untuk beralih adalah dengan menggunakan Tugas ganda

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

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

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

Menggunakan 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
sumber
4

Cara termudah untuk beralih antara 1 dan 0 adalah mengurangi 1.

def toggle(value):
    return 1 - value
Kelinci
sumber
4

Menggunakan penangan pengecualian

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

Oke, saya yang terburuk:

masukkan deskripsi gambar di sini

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

Bagaimana dengan sakelar imajiner yang menyimpan tidak hanya sakelar saat ini, tetapi beberapa nilai lain yang terkait dengannya?

toggle = complex.conjugate

Simpan nilai + atau - di sebelah kiri, dan nilai yang tidak bertanda tangan di sebelah kanan:

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

Zero juga berfungsi:

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

Dengan mudah mengambil nilai sakelar saat ini ( Truedan Falsemewakili + dan -), nilai LHS (nyata), atau nilai RHS (imajiner):

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

Mudah menukar LHS dan RHS (tetapi perhatikan bahwa tanda kedua nilai tidak boleh penting):

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

Tukar LHS dan RHS dengan mudah dan juga beralih pada saat bersamaan:

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

Penjaga dari kesalahan:

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

Lakukan perubahan pada LHS dan RHS:

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

... tapi hati-hati memanipulasi RHS:

>>> z = 1-1j
>>> z += 2j
>>> z
(1+1j) # whoops! toggled it!
Rick mendukung Monica
sumber
2

Variabel a dan b dapat berupa dua nilai APA SAJA, seperti 0 dan 1, atau 117 dan 711, atau "head" dan "tails". Tidak ada matematika yang digunakan, hanya pertukaran cepat nilai setiap kali sakelar diinginkan.

a = True   
b = False   

a,b = b,a   # a is now False
a,b = b,a   # a is now True
pengguna2948775
sumber
1

Saya menggunakan fungsi abs, sangat berguna pada loop

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

x akan menjadi 0.

Proteo5
sumber
0

Mari kita lakukan peretasan bingkai. Alihkan variabel dengan nama. Catatan: Ini mungkin tidak berfungsi dengan setiap runtime Python.

Misalkan Anda memiliki variabel "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
sumber
0

Jika Anda berurusan dengan variabel integer, Anda dapat menaikkan 1 dan membatasi set Anda ke 0 dan 1 (mod)

X = 0  # or X = 1
X = (X + 1)%2
Italo Nesi
sumber
0

Perpindahan antara -1 dan +1 dapat diperoleh dengan perkalian sebaris; digunakan untuk perhitungan pi dengan cara 'Leibniz' (atau serupa):

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

Anda dapat memanfaatkan indexdari 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"

Kelebihan : Tidak ada pustaka tambahan, kode penjelasan mandiri, dan bekerja dengan tipe data arbitrer.

Cons : tidak duplikat-simpan. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") akan selalu kembali"three"

gila
sumber