663

I have a list l:

l = [22, 13, 45, 50, 98, 69, 43, 44, 1]

For numbers above 45 inclusive, I would like to add 1; and for numbers less than it, 5.

I tried

[x+1 for x in l if x >= 45 else x+5]

But it gives me a syntax error. How can I achieve an ifelse like this in a list comprehension?

Dan D.
  • 73,243
  • 15
  • 104
  • 123
user225312
  • 126,773
  • 69
  • 172
  • 181

8 Answers8

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

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

Dan D.
  • 73,243
  • 15
  • 104
  • 123
user225312
  • 126,773
  • 69
  • 172
  • 181
  • 3
    Probably should use a different variable than `x` as the condition in the explanation at the bottom, since `x` is used in the example not as the condition. – tscizzle Apr 17 '15 at 20:03
  • 4
    what about only including variable in the list if a condition is met? would the else just be pass? – Charlie Parker Jul 25 '16 at 16:38
  • 15
    it seems that the conditional can also go at the end for example extracting objects with a specific condition (name in this example) `var_list = [v for v in tf.all_variables() if v.name == 'C:0']` – Charlie Parker Jul 25 '16 at 16:50
  • 42
    I found that if putting the condition in the beginning, then it requires both if and else (it must yield an element) - but putting it at the end, requires the if only (you can't put an else there). – Jeppe Dec 09 '18 at 13:07
  • 3
    @Jeppe Correct, which is an important distinction. If you only want to keep certain elements (ie: you do not necessarily want an entry to the array from every iteration) then you need to put the condition at the end. – Sam Creamer Aug 29 '19 at 17:35
  • another example of this if you just want to check for only one condition `[x*x for x in list(range(1,6)) if x%2!=0]` – omokehinde igbekoyi Jan 30 '20 at 00:56
349

The reason you're getting this error has to do with how the list comprehension is performed.

Keep in mind the following:

[ expression for item in list if conditional ]

Is equivalent to:

for item in list:
    if conditional:
        expression

Where the expression is in a slightly different format (think switching the subject and verb order in a sentence).

Therefore, your code [x+1 for x in l if x >= 45] does this:

for x in l:
    if x >= 45:
        x+1

However, this code [x+1 if x >= 45 else x+5 for x in l] does this (after rearranging the expression):

for x in l:
    if x>=45: x+1
    else: x+5
arboc7
  • 5,762
  • 2
  • 27
  • 30
  • 1
    My code **user_albums = [{'albums': links['link']} for links in _details['albums']['data'] if 'link' in links.keys() else pass]** getting error for pass in else condition – Shashank Oct 13 '13 at 15:05
  • 1
    @shihon No need for the `else pass` in a list comprehension; it's implied that you don't want the `{'albums': links['link']}` item included in the list when the condition `if 'link' in links.keys()` is met. Correct format: `user_albums = [{'albums': links['link']} for links in _details['albums']['data'] if 'link' in links.keys()]` – arboc7 Oct 18 '13 at 02:30
  • that means, if data isn't exist or null it handle this exception from its ownself?? – Shashank Oct 18 '13 at 06:31
  • @shihon When `'link' in links.keys()` is `False`, a Python list comprehension skips over the expression to add `{'albums': links['link']}` to the list. Your code expanded would behave the same way as `[x+1 for x in l if x >= 45]` in my answer above. – arboc7 Oct 19 '13 at 18:44
  • So, if there is an `else` in the `if` statment, the `for` goes in the end, but if there is no `else` the `for` goes after the initial expression? – Mauro Jul 28 '23 at 15:09
304
[x+1 if x >= 45 else x+5 for x in l]

And for a reward, here is the comment, I wrote to remember this the first time I did this error:

Python's conditional expression is a if C else b and can't be used as:

[a for i in items if C else b]

The right form is:

[a if C else b for i in items]

Even though there is a valid form:

[a for i in items if C]

But that isn't the same as that is how you filter by C, but they can be combined:

[a if tC else b for i in items if fC]
Dan D.
  • 73,243
  • 15
  • 104
  • 123
  • @Dan D. What about muliple `if`s? ie `[x+1 if x >= 45 x-1 if x<10 else x+5 for x in l]` ? I have a similiar kind of [problem](http://stackoverflow.com/questions/37582695/printing-certain-strings-different-colour-with-termcolor-colored) with the if statement – 3kstc Jun 02 '16 at 05:02
  • @3kstc: For that: `[x+1 if x >= 45 else (x-1 if x < 10 else x+5) for x in l]`. I'll look at your question. – Dan D. Jun 02 '16 at 05:33
  • @Dan D. Thanks The right form is: [a if C else b for i in items] this work for me. – Mushir Sep 29 '16 at 07:10
  • Not OP but thanks for your answer. For your last line of code, could you explain a bit for me what `for i in items if fC` does please? Does it mean that you are only using the `a if tC else b` conditional on the elements in `items` that can make `fC` true? Thanks. – Bowen Liu Nov 28 '18 at 20:24
  • @BowenLiu Yes. The point was to show the difference between the `if` in the ternary `A if C else B` and the conditional `if` in `i for i in items if p(i)`. Every comprehension can be written as statements if you name the result. `v = [A if q(i) else B for i in L if p(i)]` becomes `v = []`, `for i in L: if p(i): v.append(A if q(i) else B)`. – Dan D. Nov 30 '18 at 03:04
144

You must put the expression at the beginning of the list comprehension, an if statement at the end filters elements!

[x+1 if x >= 45 else x+5 for x in l]
Dan D.
  • 73,243
  • 15
  • 104
  • 123
AndiDog
  • 68,631
  • 21
  • 159
  • 205
  • 32
    +1 for explicitly distinguishing the role of conditionals at the beginning of the comprehension vs. at the end. You can do both at the same time, too; e.g. `['upper' if item.isupper() else 'lower' for item in 'Omg! paNCAkEs!!!' if item.isalpha()]` – Air Oct 14 '13 at 21:55
  • Great! Thank you, Is there an option to use else if – vinSan Aug 26 '20 at 00:50
  • 1
    @vinSan If you want to go as far as using an elif in your list comprehension, you're likely to have already surpassed the level of complexity a list comprehension was intended to be used for. Put your logic in a function and call it from your list comprehension instead. – pfabri Jan 11 '21 at 15:38
41

Like in [a if condition1 else b for i in list1 if condition2], the two ifs with condition1 and condition2 doing two different things. The part (a if condition1 else b) is from a lambda expression:

lambda x: a if condition1 else b

while the other condition2 is another lambda:

lambda x: condition2

Whole list comprehension can be regard as combination of map and filter:

map(lambda x: a if condition1 else b, filter(lambda x: condition2, list1))
Xiaojun Chen
  • 1,222
  • 2
  • 12
  • 21
  • Quite a good mapping to `map` and `filter` for two conditional snippets. – Drake Guan Jun 06 '21 at 12:53
  • 1
    can we have list comprehension without a for loop and just if/else to put a single default value inside the list and later extend it if required? i.e. result = `[ 'hello' if x == 1 ]`. This is giving a syntax error. – y_159 Jun 20 '22 at 02:24
22

You can also put the conditional expression in brackets inside the list comprehension:

    l = [22, 13, 45, 50, 98, 69, 43, 44, 1]
    print [[x+5,x+1][x >= 45] for x in l]

[false,true][condition] is the syntax

Stefan Gruenwald
  • 2,582
  • 24
  • 30
17

I just had a similar problem, and found this question and the answers really useful. Here's the part I was confused about. I'm writing it explicitly because no one actually stated it simply in English:

The iteration goes at the end.

Normally, a loop goes

for this many times:
    if conditional: 
        do this thing
    else:
        do something else  

Everyone states the list comprehension part simply as the first answer did,

[ expression for item in list if conditional ] 

but that's actually not what you do in this case. (I was trying to do it that way)

In this case, it's more like this:

[ expression if conditional else other thing for this many times ] 
szeitlin
  • 3,197
  • 2
  • 23
  • 19
6

You could move the conditional to:

v = [22, 13, 45, 50, 98, 69, 43, 44, 1]
[ (x+1 if x >=45 else x+5)  for x in v ]

But it's starting to look a little ugly, so you might be better off using a normal loop. Note that I used v instead of l for the list variable to reduce confusion with the number 1 (I think l and O should be avoided as variable names under any circumstances, even in quick-and-dirty example code).

Jeet
  • 38,594
  • 7
  • 49
  • 56