Làm thế nào để kiểm tra nhiều biến so với một giá trị?


644

Tôi đang cố gắng tạo một hàm sẽ so sánh nhiều biến với một số nguyên và xuất ra một chuỗi gồm ba chữ cái. Tôi đã tự hỏi nếu có một cách để dịch cái này sang Python. Vì vậy, nói:

x = 0
y = 1
z = 3
mylist = []

if x or y or z == 0 :
    mylist.append("c")
if x or y or z == 1 :
    mylist.append("d")
if x or y or z == 2 :
    mylist.append("e")
if x or y or z == 3 : 
    mylist.append("f")

trong đó sẽ trả về một danh sách:

["c", "d", "f"]

Có phải bất cư thứ gì như thế này đều được?


5
sử dụng 1trong (tuple)

2
Khi bạn muốn đánh giá một danh sách các câu lệnh theo bất kỳ / tất cả các cách bạn có thể sử dụng any/ allhàm. Ví dụ: all([1, 2, 3, 4, False])sẽ trả về Sai all([True, 1, 2, 3])sẽ trả về Đúng any([False, 0, 0, False])sẽ trả về Sai any([False, 0, True, False])sẽ trả về Đúng
eddd

4
Câu hỏi này là một mục tiêu trùng lặp rất phổ biến, nhưng tôi nghĩ nó không tối ưu cho mục đích đó. Hầu hết mọi người cố gắng làm một cái gì đó giống như if x == 0 or 1:, tất nhiên tương tự if x or y == 0:, nhưng có thể hơi khó hiểu cho người mới dù sao. Với số lượng lớn "Tại sao tôi không x == 0 or 1làm việc?" câu hỏi, tôi muốn sử dụng câu hỏi này như là mục tiêu trùng lặp chính của chúng tôi cho những câu hỏi này.
Aran-Fey

1
Cẩn thận hơn khi so sánh với các giá trị "falsey" như 0, 0.0hoặc False. Bạn có thể dễ dàng viết mã sai cho câu trả lời "đúng".
smci

Câu trả lời:


850

Bạn hiểu sai cách các biểu thức boolean hoạt động; họ không làm việc như một câu tiếng Anh và đoán rằng bạn đang nói về cùng một so sánh cho tất cả các tên ở đây. Bạn đang tìm kiếm:

if x == 1 or y == 1 or z == 1:

xyđược đánh giá theo cách khác ( Falsenếu 0, Truenếu không).

Bạn có thể rút ngắn việc sử dụng kiểm tra ngăn chặn đối với một tuple :

if 1 in (x, y, z):

hoặc tốt hơn vẫn là:

if 1 in {x, y, z}:

sử dụng aset để tận dụng bài kiểm tra thành viên chi phí không đổi ( inmất một khoảng thời gian cố định cho dù toán hạng bên trái là gì).

Khi bạn sử dụng or, python xem mỗi bên của toán tử là các biểu thức riêng biệt . Biểu thức x or y == 1được coi là lần đầu tiên kiểm tra boolean x, sau đó nếu đó là Sai, biểu thức y == 1được kiểm tra.

Điều này là do ưu tiên nhà điều hành . Các ornhà khai thác có độ ưu tiên thấp hơn so với ==thử nghiệm, vì vậy sau này được đánh giá đầu tiên .

Tuy nhiên, ngay cả khi đây không phải là trường hợp và biểu thức x or y or z == 1thực sự được hiểu là (x or y or z) == 1thay vào đó, điều này vẫn sẽ không làm những gì bạn mong đợi nó sẽ làm.

x or y or zsẽ đánh giá đối số đầu tiên là 'trung thực', ví dụ: không False, số 0 hoặc trống (xem biểu thức boolean để biết chi tiết về những gì Python cho là sai trong ngữ cảnh boolean).

Vì vậy, đối với các giá trị x = 2; y = 1; z = 0, x or y or zsẽ giải quyết 2, bởi vì đó là giá trị giống như thật đầu tiên trong các đối số. Sau đó 2 == 1sẽ False, mặc dù y == 1sẽ được True.

Điều tương tự sẽ áp dụng cho nghịch đảo; kiểm tra nhiều giá trị đối với một biến duy nhất; x == 1 or 2 or 3sẽ thất bại vì những lý do tương tự. Sử dụng x == 1 or x == 2 or x == 3hoặc x in {1, 2, 3}.


116
Tôi sẽ không nhanh chóng đi đến setphiên bản. Tuple rất rẻ để tạo và lặp đi lặp lại. Trên máy của tôi ít nhất, bộ dữ liệu nhanh hơn bộ miễn là kích thước của bộ dữ liệu khoảng 4-8 phần tử. Nếu bạn phải quét nhiều hơn thế, hãy sử dụng một bộ, nhưng nếu bạn đang tìm kiếm một mục trong số 2-4 khả năng, một tuple vẫn nhanh hơn! Nếu bạn có thể sắp xếp cho trường hợp có khả năng nhất là lần đầu tiên trong tuple, thì chiến thắng thậm chí còn lớn hơn: (bài kiểm tra của tôi timeit.timeit('0 in {seq}'.format(seq=tuple(range(9, -1, -1)))):)
SingleNegationElimination

57
@dequestarmappartialsetattr: Trong Python 3.3 trở lên, tập hợp được lưu trữ dưới dạng hằng số, bỏ qua thời gian tạo hoàn toàn, loại bỏ thời gian tạo. Các bộ dữ liệu thể rẻ để tạo ra khi Python lưu trữ một bó của chúng để tránh bộ nhớ, tạo ra sự khác biệt lớn nhất với các bộ ở đây.
Martijn Pieters

13
@dequestarmappartialsetattr: Nếu bạn chỉ dành thời gian kiểm tra thành viên, đối với các bộ số nguyên và bộ dữ liệu nhanh như nhau cho kịch bản lý tưởng; phù hợp với yếu tố đầu tiên. Sau đó tuples mất ra bộ.
Martijn Pieters

17
@MartijnPieters: Sử dụng setký hiệu bằng chữ cho bài kiểm tra này không phải là một khoản tiết kiệm trừ khi nội dung của setchữ cũng là chữ, phải không? if 1 in {x, y, z}:không thể cache set, bởi vì x, yzcó thể thay đổi, do đó, hoặc nhu cầu giải pháp để xây dựng một tuplehay settừ đầu, và tôi nghi ngờ bất cứ điều gì tra cứu tiết kiệm bạn có thể nhận được khi kiểm tra các thành viên sẽ được che khuất bởi lớn hơn setthời gian sáng tạo.
ShadowRanger

9
@ShadowRanger: có, tối ưu hóa lổ nhìn trộm (có thể cho in [...]hoặc in {...}) chỉ hoạt động nếu nội dung của danh sách hoặc bộ cũng là những chữ không thay đổi.
Martijn Pieters

96

Vấn đề của bạn được giải quyết dễ dàng hơn với cấu trúc từ điển như:

x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]

21
Hoặc thậm chí d = "cdef"dẫn đếnMyList = ["cdef"[k] for k in [x, y, z]]
aragaer

9
hoặcmap(lambda i: 'cdef'[i], [x, y, z])
dansalmo

3
@MJM thứ tự đầu ra không được xác định bởi dict, nó được xác định theo thứ tự của danh sách[x, y, z]
dansalmo

1
Ngoài việc hiểu danh sách mà tôi chưa hoàn toàn quen thuộc, hầu hết chúng ta đều có cùng một phản xạ: xây dựng chính tả đó!
LoneWanderer

66

Như Martijn Pieters đã nêu, định dạng chính xác và nhanh nhất là:

if 1 in {x, y, z}:

Sử dụng lời khuyên của anh ấy, giờ đây bạn sẽ có các câu lệnh if riêng biệt để Python sẽ đọc từng câu lệnh cho dù câu lệnh trước là Truehay False. Nhu la:

if 0 in {x, y, z}:
    mylist.append("c")
if 1 in {x, y, z}:
    mylist.append("d")
if 2 in {x, y, z}:
    mylist.append("e")
...

Điều này sẽ hoạt động, nhưng nếu bạn cảm thấy thoải mái khi sử dụng từ điển (xem những gì tôi đã làm ở đó), bạn có thể làm sạch nó bằng cách tạo một từ điển ban đầu ánh xạ các số thành các chữ cái bạn muốn, sau đó chỉ cần sử dụng một vòng lặp for:

num_to_letters = {0: "c", 1: "d", 2: "e", 3: "f"}
for number in num_to_letters:
    if number in {x, y, z}:
        mylist.append(num_to_letters[number])

45

Cách viết trực tiếp x or y or z == 0

if any(map((lambda value: value == 0), (x,y,z))):
    pass # write your logic.

Nhưng tôi không nghĩ rằng, bạn thích nó. :) Và cách này là xấu xí.

Một cách khác (tốt hơn) là:

0 in (x, y, z)

Rất nhiều BTW ifcó thể được viết như một cái gì đó như thế này

my_cases = {
    0: Mylist.append("c"),
    1: Mylist.append("d")
    # ..
}

for key in my_cases:
    if key in (x,y,z):
        my_cases[key]()
        break

8
Trong ví dụ của bạn về dictthay vì một khóa, bạn sẽ gặp lỗi vì giá trị trả về .appendNonevà gọi Nonecho một AttributeError. Nói chung, tôi đồng ý với phương pháp này.
SethMMorton

2
dict thay vì một khóa là sai, bạn sẽ nhận được Mylist = ['c', 'd'] khi từ điển được khởi tạo ngay cả khi bạn nhận xét phần "
for..loop

1
Trong ví dụ đầu tiên của bạn filtersẽ tốt hơn map, vì nó sẽ chỉ trả về các trường hợp mà lambda đánh giá là đúng
Alex

1
Một sự hiểu biết đơn giản hơn nhiều so với bản đồ của lambda:any(v == 0 for v in (x, y, z))
wjandrea

35

Nếu bạn rất lười biếng, bạn có thể đặt các giá trị bên trong một mảng. Nhu la

list = []
list.append(x)
list.append(y)
list.append(z)
nums = [add numbers here]
letters = [add corresponding letters here]
for index in range(len(nums)):
    for obj in list:
        if obj == num[index]:
            MyList.append(letters[index])
            break

Bạn cũng có thể đặt các số và chữ cái trong một từ điển và thực hiện nó, nhưng điều này có thể phức tạp hơn rất nhiều so với các câu lệnh đơn giản. Đó là những gì bạn nhận được khi cố gắng trở nên lười biếng hơn :)

Một điều nữa, của bạn

if x or y or z == 0:

sẽ biên dịch, nhưng không phải theo cách bạn muốn. Khi bạn chỉ cần đặt một biến trong một câu lệnh if (ví dụ)

if b

chương trình sẽ kiểm tra nếu biến không phải là null. Một cách khác để viết tuyên bố trên (có ý nghĩa hơn) là

if bool(b)

Bool là một hàm sẵn có trong python, về cơ bản thực hiện lệnh xác minh một câu lệnh boolean (Nếu bạn không biết đó là gì, đó là những gì bạn đang cố gắng thực hiện trong câu lệnh if của mình ngay bây giờ :))

Một cách lười biếng khác mà tôi tìm thấy là:

if any([x==0, y==0, z==0])

3
-1 Có rất nhiều thực hành xấu ở đây. listlà một dựng sẵn Python; sử dụng tên khác thay thế, xyzví dụ như. Tại sao bạn xây dựng danh sách theo bốn bước khi bạn có thể làm một, tức là xyz = [x, y, z]? Đừng sử dụng danh sách song song, thay vào đó hãy sử dụng một lệnh. Nói chung, giải pháp này phức tạp hơn nhiều so với ThatGuyRussell . Ngoài ra đối với phần cuối cùng, tại sao không làm một sự hiểu biết, tức là any(v == 0 for v in (x, y, z))? Ngoài ra mảng là một cái gì đó khác trong Python.
wjandrea

32

Để kiểm tra xem một giá trị có được chứa trong một tập hợp các biến không, bạn có thể sử dụng các mô đun sẵn có itertoolsoperator.

Ví dụ:

Nhập khẩu:

from itertools import repeat
from operator import contains

Khai báo các biến:

x = 0
y = 1
z = 3

Tạo ánh xạ của các giá trị (theo thứ tự bạn muốn kiểm tra):

check_values = (0, 1, 3)

Sử dụng itertoolsđể cho phép lặp lại các biến:

check_vars = repeat((x, y, z))

Cuối cùng, sử dụng maphàm để tạo một trình vòng lặp:

checker = map(contains, check_vars, check_values)

Sau đó, khi kiểm tra các giá trị (theo thứ tự ban đầu), sử dụng next():

if next(checker)  # Checks for 0
    # Do something
    pass
elif next(checker)  # Checks for 1
    # Do something
    pass

Vân vân...

Điều này có một lợi thế so với lambda x: x in (variables)operatorlà một mô-đun sẵn có và nhanh hơn và hiệu quả hơn so với việc sử dụng lambdađể tạo ra một chức năng tại chỗ tùy chỉnh.

Một tùy chọn khác để kiểm tra xem có giá trị khác không (hoặc Sai) trong danh sách không:

not (x and y and z)

Tương đương:

not all((x, y, z))

2
Điều này không trả lời câu hỏi của OP. Nó chỉ bao gồm trường hợp đầu tiên trong ví dụ được cung cấp.
wallacer

31

Đặt là cách tiếp cận tốt ở đây, vì nó ra lệnh cho các biến, dường như mục tiêu của bạn ở đây. {z,y,x}{0,1,3}bất cứ thứ tự nào của các tham số.

>>> ["cdef"[i] for i in {z,x,y}]
['c', 'd', 'f']

Bằng cách này, toàn bộ giải pháp là O (n).


5
Bạn nên thêm một mô tả về những gì mã của bạn hoàn thành và cách thực hiện nó. Câu trả lời ngắn chỉ sử dụng mã không được khuyến khích
Raniz

31

Tất cả các câu trả lời xuất sắc được cung cấp ở đây tập trung vào yêu cầu cụ thể của poster gốc và tập trung vào if 1 in {x,y,z}giải pháp được đưa ra bởi Martijn Pieters.
Điều họ bỏ qua là hàm ý rộng hơn của câu hỏi:
Làm cách nào để kiểm tra một biến đối với nhiều giá trị?
Giải pháp được cung cấp sẽ không hoạt động đối với các lần truy cập một phần nếu sử dụng chuỗi chẳng hạn:
Kiểm tra xem chuỗi "Wild" có ở nhiều giá trị không

>>> x = "Wild things"
>>> y = "throttle it back"
>>> z = "in the beginning"
>>> if "Wild" in {x, y, z}: print (True)
... 

hoặc là

>>> x = "Wild things"
>>> y = "throttle it back"
>>> z = "in the beginning"
>>> if "Wild" in [x, y, z]: print (True)
... 

đối với kịch bản này, dễ dàng nhất để chuyển đổi thành một chuỗi

>>> [x, y, z]
['Wild things', 'throttle it back', 'in the beginning']
>>> {x, y, z}
{'in the beginning', 'throttle it back', 'Wild things'}
>>> 

>>> if "Wild" in str([x, y, z]): print (True)
... 
True
>>> if "Wild" in str({x, y, z}): print (True)
... 
True

Tuy nhiên, cần lưu ý, như đã đề cập bởi @codeforester, các ràng buộc từ bị mất với phương thức này, như trong:

>>> x=['Wild things', 'throttle it back', 'in the beginning']
>>> if "rot" in str(x): print(True)
... 
True

3 chữ cái rottồn tại kết hợp trong danh sách nhưng không phải là một từ riêng lẻ. Thử nghiệm cho "mục nát" sẽ thất bại nhưng nếu một trong các mục trong danh sách là "mục nát", điều đó cũng sẽ thất bại.
Kết quả cuối cùng, hãy cẩn thận với tiêu chí tìm kiếm của bạn nếu sử dụng phương pháp này và lưu ý rằng nó có giới hạn này.


30

Tôi nghĩ rằng điều này sẽ xử lý nó tốt hơn:

my_dict = {0: "c", 1: "d", 2: "e", 3: "f"}

def validate(x, y, z):
    for ele in [x, y, z]:
        if ele in my_dict.keys():
            return my_dict[ele]

Đầu ra:

print validate(0, 8, 9)
c
print validate(9, 8, 9)
None
print validate(9, 8, 2)
e

30

Nếu bạn muốn sử dụng if, các câu lệnh khác sau đây là một giải pháp khác:

myList = []
aList = [0, 1, 3]

for l in aList:
    if l==0: myList.append('c')
    elif l==1: myList.append('d')
    elif l==2: myList.append('e')
    elif l==3: myList.append('f')

print(myList)

26
d = {0:'c', 1:'d', 2:'e', 3: 'f'}
x, y, z = (0, 1, 3)
print [v for (k,v) in d.items() if x==k or y==k or z==k]

26

Mã này có thể hữu ích

L ={x, y, z}
T= ((0,"c"),(1,"d"),(2,"e"),(3,"f"),)
List2=[]
for t in T :
if t[0] in L :
    List2.append(t[1])
    break;

12

Bạn có thể thử phương pháp hiển thị dưới đây. Trong phương pháp này, bạn sẽ có quyền tự do chỉ định / nhập số lượng biến bạn muốn nhập.

mydict = {0:"c", 1:"d", 2:"e", 3:"f"}
mylist= []

num_var = int(raw_input("How many variables? ")) #Enter 3 when asked for input.

for i in range(num_var): 
    ''' Enter 0 as first input, 1 as second input and 3 as third input.'''
    globals()['var'+str('i').zfill(3)] = int(raw_input("Enter an integer between 0 and 3 "))
    mylist += mydict[globals()['var'+str('i').zfill(3)]]

print mylist
>>> ['c', 'd', 'f']

10

Giải pháp một dòng:

mylist = [{0: 'c', 1: 'd', 2: 'e', 3: 'f'}[i] for i in [0, 1, 2, 3] if i in (x, y, z)]

Hoặc là:

mylist = ['cdef'[i] for i in range(4) if i in (x, y, z)]

9

Có lẽ bạn cần công thức trực tiếp cho các bit đầu ra được thiết lập.

x=0 or y=0 or z=0   is equivalent to x*y*z = 0

x=1 or y=1 or z=1   is equivalent to (x-1)*(y-1)*(z-1)=0

x=2 or y=2 or z=2   is equivalent to (x-2)*(y-2)*(z-2)=0

Hãy ánh xạ tới các bit: 'c':1 'd':0xb10 'e':0xb100 'f':0xb1000

Quan hệ của isc (là 'c'):

if xyz=0 then isc=1 else isc=0

Sử dụng toán học nếu công thức https://youtu.be/KAdKCgBGK0k?list=PLnI9xbPdZUAmUL8htSl6vToPQRRN3hhFp&t=315

[c]: (xyz=0 and isc=1) or (((xyz=0 and isc=1) or (isc=0)) and (isc=0))

[d]: ((x-1)(y-1)(z-1)=0 and isc=2) or (((xyz=0 and isd=2) or (isc=0)) and (isc=0))

...

Kết nối các công thức này bằng logic sau:

  • logic andlà tổng bình phương của phương trình
  • logic orlà sản phẩm của phương trình

và bạn sẽ có tổng phương trình tính tổng và bạn có tổng công thức tính tổng

thì tổng & 1 là c, tổng & 2 là d, tổng & 4 là e, tổng & 5 là f

Sau này, bạn có thể hình thành mảng được xác định trước trong đó chỉ mục của các phần tử chuỗi sẽ tương ứng với chuỗi sẵn sàng.

array[sum] cung cấp cho bạn chuỗi.


7

Nó có thể được thực hiện dễ dàng như

for value in [var1,var2,var3]:
     li.append("targetValue")

6

Cách đại diện nhất để thể hiện mã giả của bạn trong Python sẽ là:

x = 0
y = 1
z = 3
mylist = []

if any(v == 0 for v in (x, y, z)):
    mylist.append("c")
if any(v == 1 for v in (x, y, z)):
    mylist.append("d")
if any(v == 2 for v in (x, y, z)):
    mylist.append("e")
if any(v == 3 for v in (x, y, z)):
    mylist.append("f")

1
Cách tiếp cận này phổ quát hơn `if 2 in (x, y, z): mylist.append ('e')` vì cho phép so sánh tùy ý (ví dụ if any(v >= 42 for v in (x, y, z)):). Và hiệu suất của cả 3 phương pháp ( 2 in {x,y,z}, 2 in (x,y,z), any(_v == 2 for _v in (x,y,z))) có vẻ là gần như giống nhau trong CPython3.6 (xem Gist )
imposeren

5

Để kiểm tra nhiều biến với một giá trị duy nhất: if 1 in {a,b,c}:

Để kiểm tra nhiều giá trị với một biến: if a in {1, 2, 3}:


4

Có vẻ như bạn đang xây dựng một loại mật mã Caesar.

Một cách tiếp cận tổng quát hơn nhiều là đây:

input_values = (0, 1, 3)
origo = ord('c')
[chr(val + origo) for val in inputs]

đầu ra

['c', 'd', 'f']

Không chắc chắn nếu đó là một tác dụng phụ mong muốn của mã của bạn, nhưng thứ tự đầu ra của bạn sẽ luôn được sắp xếp.

Nếu đây là những gì bạn muốn, dòng cuối cùng có thể được thay đổi thành:

sorted([chr(val + origo) for val in inputs])

2

Bạn có thể sử dụng từ điển:

x = 0
y = 1
z = 3
list=[]
dict = {0: 'c', 1: 'd', 2: 'e', 3: 'f'}
if x in dict:
    list.append(dict[x])
else:
    pass

if y in dict:
    list.append(dict[y])
else:
    pass
if z in dict:
    list.append(dict[z])
else:
    pass

print list

1
Điều này có thể nối thêm sau đó một lần này. Bộ?
Sergei

2

Nếu không có lệnh, hãy thử giải pháp này:

x, y, z = 0, 1, 3    
offset = ord('c')
[chr(i + offset) for i in (x,y,z)]

và đưa ra:

['c', 'd', 'f']

0

Điều này sẽ giúp bạn.

def test_fun(val):
    x = 0
    y = 1
    z = 2
    myList = []
    if val in (x, y, z) and val == 0:
        myList.append("C")
    if val in (x, y, z) and val == 1:
        myList.append("D")
    if val in (x, y, z) and val == 2:
        myList.append("E")

test_fun(2);

0

Bạn có thể đoàn kết này

x = 0
y = 1
z = 3

trong một biến.

In [1]: xyz = (0,1,3,) 
In [2]: mylist = []

Thay đổi điều kiện của chúng tôi như:

In [3]: if 0 in xyz: 
    ...:     mylist.append("c") 
    ...: if 1 in xyz: 
    ...:     mylist.append("d") 
    ...: if 2 in xyz: 
    ...:     mylist.append("e") 
    ...: if 3 in xyz:  
    ...:     mylist.append("f") 

Đầu ra:

In [21]: mylist                                                                                
Out[21]: ['c', 'd', 'f']

0

Vấn đề

Trong khi mẫu để thử nghiệm nhiều giá trị

>>> 2 in {1, 2, 3}
True
>>> 5 in {1, 2, 3}
False

là rất dễ đọc và đang làm việc trong nhiều tình huống, có một cạm bẫy:

>>> 0 in {True, False}
True

Nhưng chúng tôi muốn có

>>> (0 is True) or (0 is False)
False

Giải pháp

Một khái quát của biểu thức trước được dựa trên câu trả lời từ ytpillai :

>>> any([0 is True, 0 is False])
False

có thể được viết là

>>> any(0 is item for item in (True, False))
False

Trong khi biểu thức này trả về kết quả đúng, nó không thể đọc được như biểu thức đầu tiên :-(

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.