# if 'a' or 'b' in L, where L is a list (Python)

## Question:

I am having trouble with the following logic:

Lets say I have a list `L = ['a', 'b', 'c']`

Both items are in the list…

```
if ('a' or 'b') in L:
print 'it's there!'
else:
print 'No sorry'
```

prints `It's there!`

Only the first item is in the list…

```
if ('a' or 'd') in L:
print 'it's there!'
else:
print 'No sorry'
```

prints `It's there!`

Neither item in the list…

```
if ('e' or 'd') in L:
print 'it's there!'
else:
print 'No sorry'
```

prints `No sorry`

**Here’s the confusing one** Only the *second* item in the list…

```
if ('e' or 'a') in L:
print 'it's there!'
else:
print 'No sorry'
```

prints `No sorry`

I do not understand why this is not registering as a true statement. How does this generalize to an **or** statement with *n* conditionals?

_{Forehead-slapping easy answer in 3,2,1…}

## Answers:

Use this instead:

```
if 'a' in L or 'b' in L:
```

If we want to check if *all* these of this “items” are in the list, `all`

and a generator comprehension is your friend:

```
items = 'a', 'b', 'c'
if all(i in L for i in items):
```

Or if *any* of these items are in the list, use `any`

:

```
if any(i in L for i in items)
```

Let’s break down the expression:

`('e' or 'a')`

will first check if `'e'`

is True. If it is, the expression will return `'e'`

. If not, it will return `'a'`

.

Since all non-empty strings returns `True`

, this expression will always return `'e'`

. This means that `if ('e' or 'a') in L:`

can be translated to `if 'e' in L`

, which in this case is `False`

.

A more generic way to check if a list contains at least one value of a set of values, is to use the `any`

function coupled with a generator expression.

```
if any(c in L for c in ('a', 'e')):
```

Strings (except an empy string) will always evaluate to `True`

when they are evaluated as a boolean. While evaluating with `or/and`

both will return `True`

, but there is a little difference between them:

```
print 'a' or 'b' # Output: a
print 'a' and 'b' # Output: b
```

`or`

: will return the first string

`and`

: will return the last string

When you do

```
if ('a' or 'b') in L:
```

, it will check `'a' or 'b'`

which is `'a'`

and then check if `'a'`

is in `L`

. Something similar happens with the other cases (based on what I explained before).

So when you do

```
if ('e' or 'a') in L:
```

, `'e' or 'a'`

will evaluate to `'e'`

and therefore it will print `'No Sorry'`

, because `'e'`

**is not** in `L`

.

What you must do is compare whether elements are in the list **separately**:

```
if 'a' in L or 'b' in L:
if 'a' in L or 'd' in L:
if 'e' in L or 'd' in L:
if 'e' in L or 'a' in L:
```

The trick to the output you’re getting is that `and`

and `or`

in Python always evaluate to one of their operands — generally the one that had to be evaluated last to determine the truthiness of the operation:

```
1 or 2 # returns 1 because since 1 is true, there's no need to evaluate the second argument.
1 or 0 # returns 1, same thing.
0 or 2 # returns 2 because 0 is false, so we need to evaluate the second arg to check whether the operation is true.
0 or "" # returns "" (both 0 and "" are false).
1 and 2 # returns 2 because for an and operation to be true, both its operands need to be checked for truthiness.
0 and 2 # returns 0, because we know that if the first operand is false, so is the whole operation.
0 and None # Still returns 0, we don't even need to check the second operand.
```

So when you’re evaluating `(1 or 2) in [1, 3, 5]`

(where in truth you want `1 in [1, 3, 5] or 2 in [1, 3, 5]`

), what really happens is `(1 or 2)`

is evaluated to `1`

, and your operation becomes `1 in [1, 3, 5]`

.