如何针对一个值测试多个变量?


644

我正在尝试制作一个将多个变量与一个整数进行比较并输出三个字母的字符串的函数。我想知道是否有一种方法可以将其转换为Python。所以说:

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

这将返回以下列表:

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

这样的事情可能吗?


5
使用1在(元组)

2
当您想以任何/所有方式评估语句列表时,可以使用any/ all函数。例如:all([1, 2, 3, 4, False])将返回False all([True, 1, 2, 3])将返回True any([False, 0, 0, False])将返回False any([False, 0, True, False])将返回True
eddd

4
这个问题是一个非常受欢迎的重复目标,但是我认为这不是最理想的选择。大多数人都尝试做类似的事情if x == 0 or 1:,这当然类似于if x or y == 0:,但是对于新手来说还是有些困惑。鉴于“为什么我不x == 0 or 1工作?”的数量如此之多问题,我宁愿将此问题用作这些问题的规范重复目标。
阿兰·费

1
比较“falsey”的价值观一样时要格外小心00.0False。您很容易编写出错误的代码,从而给出正确的答案。
smci

Answers:


850

您误解了布尔表达式是如何工作的。它们不像英文句子那样工作,并且猜测您在这里对所有名称都使用相同的比较。您正在寻找:

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

xy以其他方式自行评估(False如果为0,则为True)。

您可以使用针对元组的容纳测试来缩短该时间:

if 1 in (x, y, z):

还是更好:

if 1 in {x, y, z}:

使用aset来利用固定成本的成员资格测试(in无论左侧操作数是多少,都花费固定的时间)。

使用时or,python会将运算符的每一面视为单独的表达式。该表达式x or y == 1首先被视为的布尔测试x,然后如果为False,y == 1则测试该表达式。

这是由于运算符的优先级。的or操作者具有较低的优先级比所述==测试,所以后者被评估第一

但是,即使不是这种情况,并且x or y or z == 1实际上该表达式被解释为(x or y or z) == 1,该表达式仍不会执行您期望的操作。

x or y or z会求值为第一个“真实的”参数,例如,不是False,数字0或为空(有关布尔值在Python上下文中认为Python为假的详细信息,请参见布尔值表达式)。

因此,对于values x = 2; y = 1; z = 0x or y or z将解析为2,因为那是参数中的第一个真值。然后2 == 1False,即使y == 1True

反之亦然;针对单个变量测试多个值;x == 1 or 2 or 3会因为相同的原因而失败。使用x == 1 or x == 2 or x == 3x in {1, 2, 3}


116
我不会很快找到该set版本。元组的创建和迭代非常便宜。至少在我的机器上,只要元组的大小约为4-8个元素,元组就比集合快。如果您需要扫描的项目更多,请使用一组,但是如果您要寻找的项目不超过2-4种,则元组仍然更快!如果你可以安排最有可能的情况是先在元组,赢是更大:(我的测试:timeit.timeit('0 in {seq}'.format(seq=tuple(range(9, -1, -1))))
SingleNegationElimination

57
@dequestarmappartialsetattr:在Python 3.3及更高版本中,集合存储为常量,完全绕过了创建时间,从而消除了创建时间。创建元组可能会很便宜,因为Python会缓存一堆来避免内存流失,这使得此处的集合最大的不同。
马丁·彼得

13
@dequestarmappartialsetattr:如果仅对成员资格测试进行计时,则对于整数集和元组而言,在理想情况下同样快速;匹配第一个元素。之后,元组输掉了。
马丁·彼得斯

17
@MartijnPieters:set除非set文字的内容也是文字,否则使用节省的文字进行测试不是对的吗?if 1 in {x, y, z}:不能缓存set,因为xy并且z可能会更改,因此无论哪种解决方案都需要构建tupleset从头开始,并且我怀疑在检查成员资格时可能获得的任何查找节省都将被更多的set创建时间所淹没。
ShadowRanger 2016年

9
@ShadowRanger:是的,仅当列表或集合的内容也是不可变的文字时,窥孔优化(无论是for in [...]还是in {...})都起作用。
马丁·彼得斯

96

使用以下字典结构可以更轻松地解决您的问题:

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
甚至d = "cdef"导致MyList = ["cdef"[k] for k in [x, y, z]]
aragaer 2013年

9
map(lambda i: 'cdef'[i], [x, y, z])
dansalmo 2014年

3
@MJM输出顺序不是由字典决定的,而是由列表的顺序决定的[x, y, z]
dansalmo

1
除了我还不完全熟悉的列表理解能力之外,我们大多数人都具有相同的反思:建立该命令!
LoneWanderer

66

正如Martijn Pieters所说,正确且最快的格式是:

if 1 in {x, y, z}:

根据他的建议,您现在将具有单独的if语句,以便Python可以读取每个语句,无论前者是True还是False。如:

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")
...

这将起作用,但是如果您习惯使用字典(请参阅我在那做的事情),则可以通过制作一个初始字典来将数字映射到所需的字母,然后使用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

直接的写法x or y or z == 0

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

但我不认为,您喜欢它。:)这种方式很难看。

另一种方法(更好)是:

0 in (x, y, z)

BTW很多ifs可以写成这样的东西

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
在您的dict而不是键的示例中,您将得到错误,因为返回值为.appendis None,并且调用None给出了AttributeError。总的来说,我同意这种方法。
SethMMorton 2014年

2
dict而不是键是错误的,即使您注释掉“ for..loop”部分,也将在初始化字典时得到Mylist = ['c','d']
Mahmoud Elshahat

1
在您的第一个示例中filter会比更好map,因为它将仅返回lambda评估为true的实例
Alex

1
理解比一张lambda映射要简单得多:any(v == 0 for v in (x, y, z))
wjandrea

35

如果您非常懒惰,可以将值放在数组中。如

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

您也可以将数字和字母放入字典中并执行此操作,但这可能比if语句简单得多。那就是你变得更加懒惰的原因:)

还有一件事,你的

if x or y or z == 0:

会编译,但不会以您希望的方式编译。当您简单地将变量放在if语句中时(示例)

if b

程序将检查变量是否不为null。编写以上语句的另一种方法(更有意义)是

if bool(b)

Bool是python中的一个内置函数,它基本上执行验证布尔语句的命令(如果您不知道这是什么,那么它就是您现在要在if语句中创建的内容:)

我发现的另一种懒惰方式是:

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

3
-1这里有很多不好的做法。list是Python内置的;改用另一个名称,xyz例如。为什么在可以执行一个步骤时,即按四个步骤构造列表xyz = [x, y, z]?不要使用并行列表,而应使用字典。总而言之,该解决方案比ThatGuyRussell的解决方案复杂得多。同样对于最后一部分,为什么不理解,即any(v == 0 for v in (x, y, z))?此外阵列在Python别的东西。
wjandrea

32

要检查一组变量中是否包含值,可以使用内置模块 itertoolsoperator

例如:

进口:

from itertools import repeat
from operator import contains

声明变量:

x = 0
y = 1
z = 3

创建值的映射(以您要检查的顺序):

check_values = (0, 1, 3)

使用itertools允许的变量重复:

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

最后,使用该map函数创建一个迭代器:

checker = map(contains, check_vars, check_values)

然后,在检查值时(按原始顺序),请使用next()

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

等等...

这是一个优势,lambda x: x in (variables)因为operator它是内置模块,并且比必须使用lambda它来创建自定义就地功能的模块更快,更高效。

检查列表中是否存在非零(或False)值的另一个选项:

not (x and y and z)

当量:

not all((x, y, z))

2
这不能回答OP的问题。它仅在提供的示例中涵盖第一种情况。
wallacer 2014年

31

设置是这里的好方法,因为它对变量进行排序,这似乎是您的目标。{z,y,x}{0,1,3}参数的任何命令。

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

这样,整个解决方案就是O(n)。


5
您应该添加有关代码完成及其执行方式的描述。不鼓励仅使用代码的简短答案
Raniz 2015年

31

这里提供的所有出色答案都集中在原始海报的特定要求上,并集中在if 1 in {x,y,z}Martijn Pieters提出的解决方案上。
他们忽略了这个问题的更广泛含义:
如何针对多个值测试一个变量?
如果使用例如字符串,则提供的解决方案不适用于部分匹配:
测试字符串“ Wild”是否为多个值

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

要么

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

在这种情况下,最容易转换为字符串

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

但是,应注意,如所述@codeforester,使用此方法会丢失单词边界,例如:

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

这3个字母rot确实存在于列表中,但不是单个单词。测试“腐烂”将失败,但是如果列表项之一“在地狱腐烂”,那也将失败。
结果是,如果使用此方法,请注意您的搜索条件,并注意它确实有此限制。


30

我认为这样会更好地处理它:

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]

输出:

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

30

如果要使用if,则以下else语句是另一种解决方案:

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

此代码可能会有所帮助

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

您可以尝试以下显示的方法。在这种方法中,您可以自由指定/输入要输入的变量数。

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

一线解决方案:

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

要么:

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

9

也许您需要直接的公式来设置输出位。

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

让我们映射到位: 'c':1 'd':0xb10 'e':0xb100 'f':0xb1000

isc(是'c')的关系:

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

如果公式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))

...

通过以下逻辑连接这些公式:

  • 逻辑and是方程的平方和
  • 逻辑or是方程式的产物

你会有一个总和表示总和,你总和公式

那么sum&1是c,sum&2是d,sum&4是e,sum&5是f

之后,您可以形成预定义的数组,其中字符串元素的索引将对应于就绪字符串。

array[sum] 给你字符串。


7

它可以很容易地完成

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

6

用Python表示伪代码的最简便的方法是:

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
这种方法比`if if in 2(x,y,z):mylist.append('e')`更通用,因为它允许任意比较(例如if any(v >= 42 for v in (x, y, z)):)。和所有3种方法的性能(2 in {x,y,z}2 in (x,y,z)any(_v == 2 for _v in (x,y,z)))似乎是在CPython3.6几乎相同(见要点
imposeren

5

要使用一个值测试多个变量: if 1 in {a,b,c}:

要使用一个变量测试多个值: if a in {1, 2, 3}:


4

看起来您正在构建某种凯撒密码。

更为通用的方法是:

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

输出

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

不确定这是否是代码的理想副作用,但是输出的顺序将始终排序。

如果这是您想要的,可以将最后一行更改为:

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

2

您可以使用字典:

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
这一次可以追加更多。组?
谢尔盖

2

如果没有字典,请尝试以下解决方案:

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

并给出:

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

0

这将为您提供帮助。

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

你可以团结起来

x = 0
y = 1
z = 3

在一个变量中。

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

将我们的条件更改为:

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

输出:

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

0

问题

同时测试多个值的模式

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

具有很高的可读性,并且可以在许多情况下工作,但有一个陷阱:

>>> 0 in {True, False}
True

但是我们想要

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

先前表达式的一种概括是基于ytpillai的答案:

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

可以写成

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

虽然此表达式返回正确的结果,但它不如第一个表达式可读:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.