List Comprehension with If Statement

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.

List comprehension with if statement

You got the order wrong. The if should be after the for (unless it is in an if-else ternary operator)

[y for y in a if y not in b]

This would work however:

[y if y not in b else other_value for y in a]

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

Where to put the if-condition inside a list comprehension?

You are finding a single value, not a list of values. A list comprehension makes little sense here.

Your error is in putting your test in the value expression section of the list comprehension. That's not a filter, that's the part where you build the new list values from the (filtered) elements from the loop.

Put an if after the for loop part:

[i for i in range(11) if 2 * i - 4 == 0]

This builds a list with just one element, the i value for which the value is true:

>>> [i for i in range(11) if 2 * i - 4 == 0]
[2]

If you must do this in a single line, use a generator expression, then use the next() function to get the first result from that:

gen = (i for i in range(11) if 2 * i - 4 == 0)
result = next(gen)

This will get you the minimal value for i even if there were to be multiple possible values for i where the if test would be true.

A generator is lazily evaluated; the loop stops the moment i reaches a value where the if test is true, and that one value is produced. next() only returns that first value, so no more iteration takes place. It's as if you used break in a for loop (except you can continue the loop later).

Note that this can raise a StopIteration exception if the generator doesn't produce any values. You can tell next() to return a default value in that case; a second argument to next() is returned if StopIteration would be raised otherwise:

result = next(gen, None)

You can combine the generator expression in the next() call; if a generator expression is the only argument you can omit the (...) parenthesis of the generator expression, otherwise include them so that it can be distinguished from other arguments:

result = next((i for i in range(11) if 2 * i - 4 == 0), None)

List comprehension in python with multiple if statements

No need for even a single if; just use integer division

[1+i//7 for i in range (7*15)]

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.

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



Related Topics



Leave a reply



Submit