How to Use 'Else' in a List Comprehension

Is it possible to use 'else' in a list comprehension?

The syntax a if b else c is a ternary operator in Python that evaluates to a if the condition b is true - otherwise, it evaluates to c. It can be used in comprehension statements:

>>> [a if a else 2 for a in [0,1,0,3]]
[2, 1, 2, 3]

So for your example,

table = ''.join(chr(index) if index in ords_to_keep else replace_with
for index in xrange(15))

if/else in a list comprehension

You can totally do that. It's just an ordering issue:

[f(x) if x is not None else '' for x in xs]

In general,

[f(x) if condition else g(x) for x in sequence]

And, for list comprehensions with if conditions only,

[f(x) for x in sequence if condition]

Note that this actually uses a different language construct, a conditional expression, which itself is not part of the comprehension syntax, while the if after the for…in is part of list comprehensions and used to filter elements from the source iterable.


Conditional expressions can be used in all kinds of situations where you want to choose between two expression values based on some condition. This does the same as the ternary operator ?: that exists in other languages. For example:

value = 123
print(value, 'is', 'even' if value % 2 == 0 else 'odd')

if else in a list comprehension

>>> xs = [22, 13, 45, 50, 98, 69, 43, 44, 1]
>>> [x+1 if x >= 45 else x+5 for x in xs]
[27, 18, 46, 51, 99, 70, 48, 49, 6]

Do-something if <condition>, else do-something else.

Multiple if/else on list comprehensions

What you have here is not a list comprehension with conditionals (which filters out some elements of the comprehension), but a post-expression conditional of the form

x = A if (condition) else B

This assigns A if (condition) is true, otherwise it assigns B. (The syntax is a little confusing to look at, it must be admitted, but even Python is not always perfect.) You've managed to stack two of these inside each other, like this:

i**2 if i == 10 else (i-5 if i < 7 else i+5)

Reading from the right: The expression (i-5 if i < 7 else i+5) will give you i-5 if i<7, else you get i+5. Whatever value this is, it is included in the comprehension whenever i==10 is false (so, for the first and third list element).

Note that this construction has nothing to do with a list comprehension; you can use it anywhere (as long as i is defined).

i = 31
x = i**2 if i == 10 else (i-5 if i < 7 else i+5)

For comparison, here is a real conditional list comprehension: The comprehension will remove values that are equal to 10, leaving you with two elements in the result. I think this is the construction you set out to understand.

num3 = [ i**2 for i in num1 if i != 10 ]

How can I use if/else in list comprehensions?

You are missing the x before if:

lst = [x if x % 2 == 0 else 'odd' for x in range(11)]

The Python conditional expression syntax has to have both the 'true' and the 'false' expressions present, so true_expr if condition else false_expr, where one of true_expr or false_expr will be evaluated based on the truth value of the condition expression.

Demo:

>>> [x if x % 2 == 0 else 'odd' for x in range(11)]
[0, 'odd', 2, 'odd', 4, 'odd', 6, 'odd', 8, 'odd', 10]

Note that using a conditional expression doesn't filter, it always produces output. That's great for the per-iteration expression side of the list comprehenion syntax, but if you wanted to filter the input list and remove odd values altogether, then use a if condition test after the for ... in ... loop:

>>> [x for x in range(11) if x % 2 == 0]  # filtering, only even numbers
[0, 2, 4, 6, 8, 10]

Python list comprehension with if else conditions

You should

if det_chem in chem or not_matched.append(det_chem)

but that being said if you clean up a bit as per comments I think there is a much more efficient way of doing what you want. The explanation of the above is that append returns None so the whole if-condition will evaluate to False (but the item still appended to the not_matched list)

Re: efficiency:

res = [{det_chem:chem_db[det_chem]}
for det_chem in detected_chems
if det_chem in chem_db or not_matched.append(det_chem)]

This should be drastically faster - the for loop on dictionary keys is an O(n) operation while dictionaries are used precisely because lookup is O(1) so instead of retrieving the keys and comparing them one by one we use the det_chem in chem_db lookup which is hash based

Bonus: dict comprehension (to address question 2)

I am not sure why a list of one-key-dicts is built but probably what needed is a dict comprehension as in:

chem_db = {1: 2, 4: 5}
detected_chems = [1, 3]
not_matched = []
res = {det_chem: chem_db[det_chem] for det_chem in detected_chems if
det_chem in chem_db or not_matched.append(det_chem)}
# output
print(res) # {1: 2}
print(not_matched) # [3]

No way I can think of to build the not_matched list while also building res using a single list/dict comprehension.

How to use if-else in a list comprehension

It seems you're trying to use Python-like if-else syntax here. In Julia it is:

julia> arr = [1, 2, 3, 4];

julia> [if (x%2==0) x^2 else x^3 end for x in arr]
4-element Vector{Int64}:
1
4
27
16

There should be no difference in time of execution since both get parsed into the pretty much the same abstract code underneath, and will generate the exact same machine code. (The ternary operator is more readable and idiomatic for this purpose though.)

But if you did want to indulge your curiosity, make sure to run the functions once before timing them so as to avoid measuring the compilation time.

If-else List of lists comprehension

You can not do for x[0] in <iterable>, you need to use the entire inner-list/sequence. To get the result you are looking for, you can either use second level list comprehension, or just the list concatenation with one level of comprehension as below:

>>> [x if x[0]!=1 else [11]+x[1:] for x in list1]
[[11, 'one'], [2, 'two'], [3, 'three']]


Related Topics



Leave a reply



Submit