# How do I test multiple variables against a value?

I'm trying to make a function that will compare multiple variables to an integer and output a string of three letters. I was wondering if there was a way to translate this into Python. So say:

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

which would return a list of

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

Is something like this possible?

-
shouldn't the question be "test 'multiple' variables against multiple values"? – Devesh Khandelwal
use `1` in (tuple) – DNinja21

You misunderstand how boolean expressions work; they don't work like an English sentence and guess that you are talking about the same comparison for all names here. You are looking for:

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

`x` and `y` are otherwise evaluated on their own (`False` if `0`, `True` otherwise).

You can shorten that to:

``````if 1 in (x, y, z):
``````

or better still:

``````if 1 in {x, y, z}:
``````

using a `set` to take advantage of the constant-cost membership test (`in` takes a fixed amount of time whatever the left-hand operand is).

When you use `or`, python sees each side of the operator as separate expressions. The expression `x or y == 1` is treated as first a boolean test for `x`, then if that is False, the expression `y == 1` is tested.

This is due to operator precedence. The `or` operator has a lower precedence than the `==` test, so the latter is evaluated first.

However, even if this were not the case, and the expression `x or y or z == 1` was actually interpreted as `(x or y or z) == 1` instead, this would still not do what you expect it to do.

`x or y or z` would evaluate to the first argument that is 'truthy', e.g. not `False`, numeric 0 or empty (see boolean expressions for details on what Python considers false in a boolean context).

So for the values `x = 2; y = 1; z = 0`, `x or y or z` would resolve to `2`, because that is the first true-like value in the arguments. Then `2 == 1` would be `False`, even though `y == 1` would be `True`.

The same would apply to the inverse; testing multiple values against a single variable; `x == 1 or 2 or 3` would fail for the same reasons. Use `x == 1 or x == 2 or x == 3` or `x in {1, 2, 3}`.

-
can you explain a bit more why the OP misunderstands booleans? – Private
I wouldn't be so quick to go for the `set` version. Tuple's are very cheap to create and iterate over. On my machine at least, tuples are faster than sets so long as the size of the tuple is around 4-8 elements. If you have to scan more than that, use a set, but if you are looking for an item out of 2-4 possibilities, a tuple is still faster! If you can arrange for the most likely case to be first in the tuple, the win is even bigger: (my test: `timeit.timeit('0 in {seq}'.format(seq=tuple(range(9, -1, -1))))`) – SingleNegationElimination
@dequestarmappartialsetattr: In Python 3.3 and up, the set is stored as a constant, bypassing the creation time altogether, eliminating the creation time. Tuples can be cheap to create as Python caches a bundle of them to avoid memory churn, making that the biggest difference with sets here. – Martijn Pieters
@dequestarmappartialsetattr: If you time just the membership test, for integers sets and tuples are equally fast for the ideal scenario; matching the first element. After that tuples lose out to sets. – Martijn Pieters
Woah. I never realized there was a literal set notation. How long has that been there? All this time I've been writing `set(x, y, z)`, I could have been saving myself 3 characters. I find it weird that there's something so basic that I've never seen in the years I've been using Python. – ArtOfWarfare
@ArtOfWarfare: it was added to Python 3.1 and 2.7. – Martijn Pieters
@MartijnPieters: Oh. Then perhaps I should avoid it. Although many of the machines I work with have 2.7, some are only running 2.6. – ArtOfWarfare
wow, the literal set notation is a new shiny thing for me but it's available since py2.7, on July 2010, 5 years ago! docs.python.org/3/whatsnew/2.7.html – franciscod
@MartijnPieters: Using the `set` literal notation for this test isn't a savings unless the contents of the `set` literal are also literals, right? `if 1 in {x, y, z}:` can't cache the `set`, because `x`, `y` and `z` could change, so either solution needs to build a `tuple` or `set` from scratch, and I suspect whatever lookup savings you might get when checking for membership would be swamped by greater `set` creation time. – ShadowRanger
@ShadowRanger: yes, peephole optimisation (be it for `in [...]` or `in {...}`) only works if the contents of the list or set are immutable literals too. – Martijn Pieters

The direct way to write `x or y or z == 0` is

``````if any(map((lambda value: value == 0), (x,y,z))):
``````

But I dont think, you like it. :) And this way is ugly.

The other way (a better) is:

``````0 in (x, y, z)
``````

BTW lots of `if`s could be written as something like this

``````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
``````
-
In your example of the `dict` instead of a key, you will get errors because the return value of `.append` is `None`, and calling `None` gives an `AttributeError`. In general I agree with this method, though. – SethMMorton

``````x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]
``````
-
Or even `d = "cdef"` which leads to `MyList = ["cdef"[k] for k in [x, y, z]]` – aragaer
or `map(lambda i: 'cdef'[i], [x, y, z])` – dansalmo

To check if a value is contained within a set of variables you can use the inbuilt modules `itertools` and `operator`.

For example:

Imports:

``````from itertools import repeat
from operator import contains
``````

Declare variables:

``````x = 0
y = 1
z = 3
``````

Create mapping of values (in the order you want to check):

``````check_values = (0, 1, 3)
``````

Use `itertools` to allow repetition of the variables:

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

Finally, use the `map` function to create an iterator:

``````checker = map(contains, check_vars, check_values)
``````

Then, when checking for the values (in the original order), use `next()`:

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

etc...

This has an advantage over the `lambda x: x in (variables)` because `operator` is an inbuilt module and is faster and more efficient than using `lambda` which has to create a custom in-place function.

Another option for checking if there is a non-zero (or False) value in a list:

``````not (x and y and z)
``````

Equivalent:

``````not all((x, y, z))
``````
-
This doesn't answer the OP's question. It only covers the first case in the provided example. – wallacer

I think this will handle it better:

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

Output:

``````print validate(0, 8, 9)
c
print validate(9, 8, 9)
None
print validate(9, 8, 2)
e
``````
-
``````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]
``````
-

If you want to use if, else statements following is another solution:

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

If you ARE very very lazy, you can put the values inside an array. Such as

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

You can also put the numbers and letters in a dictionary and do it, but this is probably a LOT more complicated than simply if statements. That's what you get for trying to be extra lazy :)

One more thing, your

``````if x or y or z == 0:
``````

will compile, but not in the way you want it to. When you simply put a variable in an if statement (example)

``````if b
``````

the program will check if the variable is not null. Another way to write the above statement (which makes more sense) is

``````if bool(b)
``````

Bool is an inbuilt function in python which basically does the command of verifying a boolean statement (If you don't know what that is, it is what you are trying to make in your if statement right now :))

Another lazy way I found is :

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

Set is the good approach here, because it orders the variables, what seems to be your goal here. `{z,y,x}` is `{0,1,3}` whatever the order of the parameters.

``````>>> [chr(ord('c')+i) for i in {z,x,y}]
['c', 'd', 'f']
``````

the letter corresponding to a number is given here by `chr(ord('c')+i)` , where `chr` and `ord` are bridges between characters and numeric codes.

So the whole solution is O(n).

-
You should add a description of what your code accomplishes and how it does it. Short answers using only code is discouraged – Raniz

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

Previous Solution: As stated by Martijn Pieters, the correct, and fastest, format is:

``````if 1 in {x, y, z}:
``````

The one major issue that does not seem to be addressed is that you want your output list to include each letter after a true if statement.

Using only Martijn Pieters' advice you would now have:

``````if 0 in {x, y, z}:
Mylist.append("c")
elif 1 in {x, y, z}:
Mylist.append("d")
...
``````

Problem: The first if statement would return true, and you would never get to the following elif statement. So your list would simply return:

``````["c"]
``````

What you want is to have separate if statements so that python will read each statement whether the former were true or false. Such as:

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

This will work, but 'if' you are comfortable using dictionaries (see what I did there), you can clean this up by making an initial dictionary mapping the numbers to the letters you want, then just using a 'for' loop:

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

Don't get too much complicated just follow the simplest way.

`````` x = 0
y = 1
z = 3

Mylist = []

if x == 0 or y==0 or z==0:
Mylist.append('c')
elif x == 1 or y == 1 or z==1:
Mylist.append('d')
elif x==2 or y==2 or z==2:
Mylist.append('e')
elif x==3 or y==3 or z==3:
Mylist.append('f')
``````

Cheers!

-
The problem with this approach is the high likelihood of making a typo. Which is exactly what happened. `elif x==1 or y==2 or z==2:` => `elif x==2 or y==2 or z==2:` oops. Fixed now though. – Paul Rooney

All of the excellent answers provided here concentrate on the specific requirement of the original poster and concentrate on the `if 1 in {x,y,z}` solution put forward by Martijn Pieters.
What they ignore is the broader implication of the question:
How do I test one variable against multiple values?
The solution provided will not work for partial hits if using strings for example:
Test if the string "Wild" is in multiple values

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

or

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

for this scenario it's easiest to convert to a string

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

One line solution:

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

Or:

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