Cách chuyển đổi giá trị trong Python


127

Cách hiệu quả nhất để chuyển đổi giữa 0và là 1gì?


trong khi câu hỏi này hỏi làm thế nào để chuyển đổi các giá trị theo cách nhị phân một cách hiệu quả nhất, một số câu trả lời giải thích chu kỳ thông qua các giá trị (tùy ý), ví dụ stackoverflow.com/a/61041907/537865
điên

Câu trả lời:


272

Giải pháp sử dụng KHÔNG

Nếu các giá trị là boolean, cách tiếp cận nhanh nhất là sử dụng toán tử không :

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

Giải pháp sử dụng phép trừ

Nếu các giá trị là số, thì phép trừ khỏi tổng là một cách đơn giản và nhanh chóng để chuyển đổi các giá trị:

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

Giải pháp sử dụng XOR

Nếu giá trị chuyển đổi trong khoảng từ 0 đến 1 , bạn có thể sử dụng độc quyền bitwise-hoặc :

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

Kỹ thuật này khái quát cho bất kỳ cặp số nguyên nào. Bước xor-by-one được thay thế bằng hằng số xor-by-preomputing-Constant:

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

(Ý tưởng này đã được gửi bởi Nick Coghlan và sau đó được khái quát bởi @zxxc.)

Giải pháp sử dụng từ điển

Nếu các giá trị có thể băm, bạn có thể sử dụng từ điển:

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

Giải pháp sử dụng biểu thức điều kiện

Cách chậm nhất là sử dụng biểu thức điều kiện :

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

Giải pháp sử dụng itertools

Nếu bạn có nhiều hơn hai giá trị, hàm itertools. Motorcycle () cung cấp một cách nhanh chóng chung để chuyển đổi giữa các giá trị liên tiếp:

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

Lưu ý rằng trong Python 3 next()phương thức đã được thay đổi thành __next__(), vì vậy dòng đầu tiên sẽ được viết làtoggle = itertools.cycle(['red', 'green', 'blue']).__next__


Ví dụ cuối cùng có vẻ lắt léo và trực quan, nhưng không hoạt động trong Python 3+ với việc loại bỏ .next (). Có cách nào để làm cho nó hoạt động tương tự trong phiên bản sau của python không?
labarna

2
@labarna Trong Python 3, hàm .next()đã được thay thế bằng next()hàm toàn cục . Ví dụ trên sẽ là:toggle = itertools.cycle(...); next(toggle)
elpres 18/07/17

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

7
Ví dụ XOR có thể được khái quát hóa để chuyển đổi giữa các giá trị absử dụng x = x ^ (a ^ b).
zxxc

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

33

Tôi luôn luôn sử dụng:

p^=True

Nếu p là boolean, điều này sẽ chuyển giữa đúng và sai.


1
Hoàn hảo! pkhông cần phải tham khảo hai lần để phương pháp này hoạt động !! Ý tưởng nếu bạn đang thay đổi một giá trị với một tài liệu tham khảo dài.
ThorSummoner

1
Toán tử này được gọi là gì?
mix3d

4
Đây là toán tử XOR.
bastelflp

1
@ mix3d Chính xác đó là "độc quyền bitwise hoặc" (trái ngược với "độc quyền logic hoặc") - wiki.python.org/moin/BitwiseOperators . Logical XOR không có toán tử cụ thể trong Python nói chung nhưng bạn có thể thấy nó được triển khai trong một số trường hợp đặc biệt như trong mô-đun thập phân.
Taylor Edmiston

@ mix3d ^=là giả định xor bitwise
wjandrea

23

Đây là một cách không trực quan khác. Vẻ đẹp là bạn có thể xoay vòng qua nhiều giá trị và không chỉ hai [0,1]

Cho hai giá trị (chuyển đổi)

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

Đối với nhiều giá trị (nói 4)

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

Tôi không mong đợi giải pháp này cũng gần như nhanh nhất

>>> 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
vâng đó là schweet như một hạt. cảm ơn mọi người, điều này thật thú vị khi xem những người khác nhau tiếp cận vấn đề như thế nào (và nhiều thông tin.)

Thật tuyệt, đó là một cỗ máy nhà nước thu nhỏ.
kindall

tốt, cái của bạn là thú vị nhất, nhưng nó không phải là thứ mà cá nhân tôi cần cho điều tôi đang hỏi, vậy thì, tôi nghĩ rằng toán đơn giản sau đó có lẽ là tốt nhất đối với tôi, không phải là 1-x ở đó sao?

Đúng, nhưng điều đó không làm cho tốc độ khác nhau.
Máy xay sinh tố

Ai, nhưng nó sẽ làm cho nó sai mặc dù sẽ không? Một số câu trả lời tuyệt vời ở đây, đá SO!

19

Các notnhà điều hành phủ nhận biến của bạn (chuyển đổi nó thành một boolean nếu nó chưa được một). Bạn có thể có thể sử dụng 10hoán đổi cho nhau TrueFalsevì vậy chỉ cần phủ nhận nó:

toggle = not toggle

Nhưng nếu bạn đang sử dụng hai giá trị tùy ý, hãy sử dụng một dòng if:

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

1
1 nhưng toggle = 0 if toggle else 1là ngắn hơn và tổng quát hơn
luc

Xin lỗi, tôi sẽ trao đổi các biến để làm cho nó rõ ràng hơn. Tôi đã sử dụng nội tuyến ifđể chuyển đổi giữa hai biến tùy ý , không chỉ 10.
Máy xay sinh tố

14

Chỉ từ 1 đến 0, làm điều này

1-x 

x có thể mất 1 hoặc 0


Vì (trong Python 2.x, dù sao) TrueFalsethực sự là các số nguyên, mặc dù các số có __str__()phương thức dài dòng đáng ngạc nhiên , xcũng có thể Truehoặc Falseở đây. Bạn sẽ nhận được 1 hoặc 0 trở lại, mặc dù.
loại


7

Đáng ngạc nhiên không ai đề cập đến modulo phân chia cũ 2 tốt:

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

Lưu ý rằng nó tương đương với x = x - 1, nhưng lợi thế của kỹ thuật modulo là kích thước của nhóm hoặc độ dài của khoảng có thể lớn hơn chỉ bằng 2 phần tử, do đó cung cấp cho bạn một sơ đồ xen kẽ vòng tròn để lặp lại.

Bây giờ chỉ với 2, việc chuyển đổi có thể ngắn hơn một chút (sử dụng toán tử bit-khôn ngoan):

x = x ^ 1

Tôi không chắc chắn làm thế nào "số học pythonic" này là số học modulo (giống như C) (i, e, liệu "pythonic" có áp dụng không?). Tôi đoán đó chỉ là số học, hoạt động ở mọi nơi khác nơi bạn có nhị phân.
Yauhen Yakimovich

Rõ ràng là máy trạng thái hữu hạn với tuple như x = (1,2,3,0); token = 0; token = x [token] cực kỳ thú vị, vì nó có thể thậm chí còn chung chung hơn là chỉ hoạt động nhóm.
Yauhen Yakimovich

7

một cách để chuyển đổi là sử dụng nhiều bài tập

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

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

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

Sử dụng 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

Cách dễ nhất để chuyển đổi giữa 1 và 0 là trừ đi 1.

def toggle(value):
    return 1 - value

4

Sử dụng xử lý ngoại lệ

>>> 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, tôi là người tồi tệ nhất:

nhập mô tả hình ảnh ở đây

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

Làm thế nào về một chuyển đổi tưởng tượng lưu trữ không chỉ chuyển đổi hiện tại, mà một vài giá trị khác liên quan đến nó?

toggle = complex.conjugate

Lưu trữ bất kỳ giá trị + hoặc - ở bên trái và bất kỳ giá trị không dấu nào ở bên phải:

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

Không hoạt động, quá:

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

Dễ dàng truy xuất giá trị chuyển đổi hiện tại ( TrueFalseđại diện cho giá trị + và -), giá trị LHS (thực) hoặc RHS (tưởng tượng):

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

Dễ dàng trao đổi LHS và RHS (nhưng lưu ý rằng dấu hiệu của cả hai giá trị không phải là quan trọng):

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

Dễ dàng trao đổi LHS và RHS và cũng có thể chuyển đổi cùng một lúc:

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

Bảo vệ chống lại lỗi:

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

Thực hiện các thay đổi đối với LHS và RHS:

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

... nhưng hãy cẩn thận thao túng RHS:

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

2

Các biến a và b có thể là BẤT K Two hai giá trị, như 0 và 1, hoặc 117 và 711 hoặc "đầu" và "đuôi". Không có toán học nào được sử dụng, chỉ cần trao đổi nhanh các giá trị mỗi khi muốn chuyển đổi.

a = True   
b = False   

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

1

Tôi sử dụng chức năng abs, rất hữu ích trên các vòng lặp

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

x sẽ là 0.


0

Hãy thực hiện một số hack khung. Chuyển đổi một biến theo tên. Lưu ý: Điều này có thể không hoạt động với mọi thời gian chạy Python.

Giả sử bạn có một biến "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

Nếu bạn đang xử lý một biến số nguyên, bạn có thể tăng 1 và giới hạn cài đặt của mình thành 0 và 1 (mod)

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

0

Chuyển đổi giữa -1 và +1 có thể thu được bằng cách nhân nội tuyến; được sử dụng để tính pi theo cách 'Leibniz' (hoặc tương tự):

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

0

Bạn có thể sử dụng indexcủa 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"

Ưu điểm : Không có thư viện bổ sung, mã self.explanatory và làm việc với các loại dữ liệu tùy ý.

Nhược điểm : không trùng lặp-lưu. toggleValues(["one","two","duped", "three", "duped", "four"], "duped") sẽ luôn trở lại"three"

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.