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

use*_*442 594 python comparison boolean-logic if-statement match

我正在尝试创建一个函数,将多个变量与一个整数进行比较,并输出一个由三个字母组成的字符串.我想知道是否有办法将其翻译成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")
Run Code Online (Sandbox Code Playgroud)

这将返回一个列表

["c", "d", "f"]
Run Code Online (Sandbox Code Playgroud)

这样的事情可能吗?

Mar*_*ers 785

你误解了布尔表达式的工作原理; 他们不像英语句子一样工作,并猜测你在谈论所有名字的相同比较.您正在寻找:

if x == 1 or y == 1 or z == 1:
Run Code Online (Sandbox Code Playgroud)

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

您可以使用针对元组的包含测试来缩短它:

if 1 in (x, y, z):
Run Code Online (Sandbox Code Playgroud)

或者更好的是:

if 1 in {x, y, z}:
Run Code Online (Sandbox Code Playgroud)

使用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将评估为'truthy'的第一个参数,例如not False,numeric 0或empty(有关Python在布尔上下文中认为false的详细信息,请参阅布尔表达式).

因此对于值x = 2; y = 1; z = 0,x or y or z将解析为2,因为这是参数中第一个类似真值的值.那2 == 1就是False,即使y == 1True.

这同样适用于逆; 针对单个变量测试多个值; x == 1 or 2 or 3因为同样的原因会失败.使用x == 1 or x == 2 or x == 3x in {1, 2, 3}.

  • 我不会那么快去找'set`版本.元组是非常便宜的创建和迭代.至少在我的机器上,元组比集合更快,只要元组的大小约为4-8个元素.如果你必须扫描更多,使用一组,但如果你正在寻找2-4种可能的项目,元组仍然更快!如果你可以安排最有可能的情况在元组中排在第一位,那么胜利就更大了:(我的测试:`timeit.timeit('{seq}'中的'.格式(seq =元组(范围(9, - ) 1,-1))))`) (102认同)
  • @dequestarmappartialsetattr:在Python 3.3及更高版本中,该集存储为常量,完全绕过创建时间,从而消除了创建时间.元组*可以*创建起来很便宜,因为Python缓存了一大堆它们以避免内存流失,这使得这里的集合最大. (47认同)
  • @MartijnPieters:除非`set`文字的内容也是文字,否则使用`set`文字符号进行此测试不是一种节省,对吧?`如果{x,y,z}中的1:``无法缓存`set`,因为`x`,`y`和`z`可能会改变,所以任何一个解决方案都需要构建一个`tuple`或`set "从头开始,我怀疑在检查成员身份时可能会得到的任何查找节省会被更大的"set"创建时间所淹没. (13认同)
  • @dequestarmappartialsetattr:如果你的时间*只是*成员资格测试,整数集和元组在理想情况下同样快; 匹配第一个元素.在那之后,元组输掉了. (9认同)
  • @ShadowRanger:是的,窥孔优化(对于`in [...]`或`in {...}`)只有在列表或集合的内容也是不可变的文字时才有效. (5认同)
  • @Anthony:那是错误的考验; `string`不包含在序列`(word1,word2)`中.如果你有多个单词要在一个字符串中测试,你可以使用`all(在sequence_of_words_to_test中w为字符串w).或者如果你只有2或3个这样的字符串要测试,那么使用字符串中的`word1和字符串中的word2`方法,并且它们是硬编码的. (2认同)

dan*_*lmo 88

使用字典结构更容易解决您的问题:

x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]
Run Code Online (Sandbox Code Playgroud)

  • 甚至``d ="cdef"`导致`myList = ["cdef"[k]代表[x,y,z]中的k] (19认同)
  • 或者`map(lambda i:'cdef'[i],[x,y,z])` (9认同)
  • @MJM输出顺序不是由dict决定的,它是由列表`[x,y,z]的顺序决定的. (3认同)
  • 除了我还不完全习惯的列表理解之外,我们大多数人都有相同的反应:构建那个 dict ! (2认同)

Tha*_*ell 61

以前的解决方案:正如Martijn Pieters所说,正确且最快的格式是:

if 1 in {x, y, z}:
Run Code Online (Sandbox Code Playgroud)

似乎没有解决的一个主要问题是您希望输出列表在真正的if语句后包含每个字母.

仅使用Martijn Pieters的建议,您现在可以:

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")
...
Run Code Online (Sandbox Code Playgroud)

问题:第一个if语句将返回true,并且您永远不会得到以下elif语句.所以你的清单会简单地返回:

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])
Run Code Online (Sandbox Code Playgroud)

你想要的是拥有单独的if语句,以便python将读取每个语句,无论前者是真还是假.如:

if 1 in {x, y, z}:
Run Code Online (Sandbox Code Playgroud)

这样可以工作,但是"如果"你习惯使用字典(看我在那里做了什么),你可以通过制作一个初始字典将数字映射到你想要的字母来清理它,然后只使用'for'循环:

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")
...
Run Code Online (Sandbox Code Playgroud)


aka*_*Rem 44

写作的直接方式x or y or z == 0

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

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

另一种方式(更好)是:

0 in (x, y, z)
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

  • 在你的`dict`而不是key的例子中,你会得到错误,因为`.append`的返回值是`None`,而调用`None`会产生`AttributeError`.但总的来说,我同意这种方法. (6认同)
  • 字典而不是键是错误的,即使您注释掉了“for..loop”部分,当字典初始化时,您也会得到 Mylist=['c', 'd'] (3认同)
  • 理解比 lambda 的映射简单得多:`any(v == 0 for v in (x, y, z))` (3认同)
  • 在第一个示例中,“filter”会比“map”更好,因为它只会返回 lambda 计算结果为 true 的实例 (2认同)

ytp*_*lai 32

如果你非常懒,可以将值放在数组中.如

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
Run Code Online (Sandbox Code Playgroud)

您也可以将数字和字母放在字典中并执行它,但这可能比简单的语句更复杂.这就是你想要更加懒惰的结果:)

还有一件事,你的

if x or y or z == 0:
Run Code Online (Sandbox Code Playgroud)

将编译,但不是以你想要的方式编译.当你只是在if语句中放一个变量时(例子)

if b
Run Code Online (Sandbox Code Playgroud)

程序将检查变量是否为空.编写上述语句的另一种方法(更有意义)是

if bool(b)
Run Code Online (Sandbox Code Playgroud)

Bool是python中的一个内置函数,它基本上执行验证布尔语句的命令(如果你不知道那是什么,那么你现在正试着在你的if语句中做:) :)

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

if any([x==0, y==0, z==0])
Run Code Online (Sandbox Code Playgroud)

  • -1 这里有很多不好的做法。`list` 是 Python 内置函数;使用另一个名称,例如“xyz”。当你可以完成一个步骤(即“xyz = [x, y, z]”)时,为什么要分四步构建列表?不要使用并行列表,而使用字典。总而言之,这个解决方案比 [ThatGuyRussell 的](/sf/answers/2245993991/) 复杂得多。同样对于最后一部分,为什么不进行理解,即“any(v == 0 for v in (x, y, z))”?另外,[数组](https://docs.python.org/3/library/array.html) 也是 Python 中的其他东西。 (6认同)

Gui*_*hin 29

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

例如:

进口:

from itertools import repeat
from operator import contains
Run Code Online (Sandbox Code Playgroud)

声明变量:

x = 0
y = 1
z = 3
Run Code Online (Sandbox Code Playgroud)

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

check_values = (0, 1, 3)
Run Code Online (Sandbox Code Playgroud)

使用itertools允许的变量重复:

check_vars = repeat((x, y, z))
Run Code Online (Sandbox Code Playgroud)

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

checker = map(contains, check_vars, check_values)
Run Code Online (Sandbox Code Playgroud)

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

if next(checker)  # Checks for 0
    # Do something
    pass
elif next(checker)  # Checks for 1
    # Do something
    pass
Run Code Online (Sandbox Code Playgroud)

等等...

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

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

not (x and y and z)
Run Code Online (Sandbox Code Playgroud)

当量:

not all((x, y, z))
Run Code Online (Sandbox Code Playgroud)

  • 这不能回答 OP 的问题。它仅涵盖所提供示例中的第一种情况。 (2认同)

小智 27

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

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]
Run Code Online (Sandbox Code Playgroud)

输出:

print validate(0, 8, 9)
c
print validate(9, 8, 9)
None
print validate(9, 8, 2)
e
Run Code Online (Sandbox Code Playgroud)


B. *_* M. 27

Set是一个很好的方法,因为它命令变量,这似乎是你的目标.{z,y,x}{0,1,3}参数的任何命令.

>>> ["cdef"[i] for i in {z,x,y}]
['c', 'd', 'f']
Run Code Online (Sandbox Code Playgroud)

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

  • 您应该添加代码完成内容及其执行方式的说明.不鼓励仅使用代码的简短答案 (4认同)

Rol*_*ony 27

这里提供的所有优秀答案都集中在原始海报的具体要求上,并专注于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)
... 
Run Code Online (Sandbox Code Playgroud)

要么

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

对于这种情况,最容易转换为字符串

>>> [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
Run Code Online (Sandbox Code Playgroud)

然而,应该注意的是,如上所述@codeforester,使用此方法会丢失单词边界,如:

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

3个字母rot确实在列表中组合存在,但不作为单个单词存在.对"腐烂"的测试会失败,但如果其中一个列表项目"在地狱中腐烂",那么也会失败.
结果是,如果使用此方法,请注意您的搜索条件,并注意它确实有此限制.


小智 26

如果你想使用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)
Run Code Online (Sandbox Code Playgroud)


Sak*_*rma 23

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]
Run Code Online (Sandbox Code Playgroud)


小智 23

此代码可能会有所帮助

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;
Run Code Online (Sandbox Code Playgroud)


rsa*_*mei 10

在 Python 中表示伪代码的最 Pythonic 方式是:

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")
Run Code Online (Sandbox Code Playgroud)

  • 这种方法比 ` if 2 in (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 中似乎几乎相同(参见 [Gist](https://gist.github.com/imposeren/06eb52771d1b779e64d9bef525da87d8)) (2认同)

Vin*_*kal 8

一线解决方案:

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

要么:

mylist = ['cdef'[i] for i in range(4) if i in (x, y, z)]
Run Code Online (Sandbox Code Playgroud)


Sid*_*thy 8

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

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']
Run Code Online (Sandbox Code Playgroud)


Ser*_*gei 7

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

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
Run Code Online (Sandbox Code Playgroud)

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

isc(是'c')的关系:

if xyz=0 then isc=1 else isc=0
Run Code Online (Sandbox Code Playgroud)

如果公式为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] 给你字符串。


fir*_*ynx 5

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

更通用的方法是:

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

输出

['c', 'd', 'f']
Run Code Online (Sandbox Code Playgroud)

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

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

sorted([chr(val + origo) for val in inputs])
Run Code Online (Sandbox Code Playgroud)


ala*_*min 5

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

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


小智 5

它可以很容易地完成

for value in [var1,var2,var3]:
     li.append("targetValue")
Run Code Online (Sandbox Code Playgroud)