Cara mengubah nilai dengan Python


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__


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.


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

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'

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


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

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

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

4

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

def toggle(value):
    return 1 - value

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)

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!

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

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.


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

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

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)

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"

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.