# else condition in list comprehension

Discussion in 'Python' started by Luis M. Gonzalez, Jan 9, 2005.

1. ### Luis M. GonzalezGuest

Hi there,

I'd like to know if there is a way to add and else condition into a
list comprehension. I'm sure that I read somewhere an easy way to do
it, but I forgot it and now I can't find it...

for example:
z=[i+2 for i in range(10) if i%2==0]
what if I want i to be "i-2" if i%2 is not equal to 0?

Luis M. Gonzalez, Jan 9, 2005

2. ### Reinhold BirkenfeldGuest

Luis M. Gonzalez wrote:
> Hi there,
>
> I'd like to know if there is a way to add and else condition into a
> list comprehension. I'm sure that I read somewhere an easy way to do
> it, but I forgot it and now I can't find it...
>
> for example:
> z=[i+2 for i in range(10) if i%2==0]
> what if I want i to be "i-2" if i%2 is not equal to 0?

You'll have to add the condition at the front:

z = [(i+2, i-2)[i%2] for i in range(10)]

should do what you need.

Reinhold

Reinhold Birkenfeld, Jan 9, 2005

3. ### Matteo Dell'AmicoGuest

Luis M. Gonzalez wrote:
> Hi there,
>
> I'd like to know if there is a way to add and else condition into a
> list comprehension. I'm sure that I read somewhere an easy way to do
> it, but I forgot it and now I can't find it...
>
> for example:
> z=[i+2 for i in range(10) if i%2==0]
> what if I want i to be "i-2" if i%2 is not equal to 0?

You could use

[(i-2, i+2)[bool(i%2 == 0)] for i in range(10)]

or, in a less general but shorter way

[(i+2, i-2)[i%2] for i in range(10)]

or even

[i%2 and i-2 or i+2 for i in range(10)]

The "if" clause in comprehensions is used as a filter condition.

--
Ciao,
Matteo

Matteo Dell'Amico, Jan 9, 2005
4. ### Luis M. GonzalezGuest

Thank you guys!

Luis M. Gonzalez, Jan 9, 2005
5. ### Reinhold BirkenfeldGuest

Matteo Dell'Amico wrote:
> Luis M. Gonzalez wrote:
>> Hi there,
>>
>> I'd like to know if there is a way to add and else condition into a
>> list comprehension. I'm sure that I read somewhere an easy way to do
>> it, but I forgot it and now I can't find it...
>>
>> for example:
>> z=[i+2 for i in range(10) if i%2==0]
>> what if I want i to be "i-2" if i%2 is not equal to 0?

>
> You could use
>
> [(i-2, i+2)[bool(i%2 == 0)] for i in range(10)]
>
> or, in a less general but shorter way
>
> [(i+2, i-2)[i%2] for i in range(10)]
>
> or even
>
> [i%2 and i-2 or i+2 for i in range(10)]

One should note that the (cond and X or Y) construct only works if X can
never produce a false value (such as 0, "", []). In this example, it is
okay, but replace 2 with 1 and you will run into trouble for i = 1.

Reinhold

Reinhold Birkenfeld, Jan 9, 2005
6. ### Dan BishopGuest

Luis M. Gonzalez wrote:
> Hi there,
>
> I'd like to know if there is a way to add and else condition into a
> list comprehension. I'm sure that I read somewhere an easy way to do
> it, but I forgot it and now I can't find it...
>
> for example:
> z=[i+2 for i in range(10) if i%2==0]
> what if I want i [sic] to be "i-2" if i%2 is not equal to 0?

z = [i + (2, -2)[i % 2] for i in range(10)]

In general, the expression "T if C is true, or F if C is false" can be
written as (F, T)[bool(C)]. (If you know that C will always be either
0 or 1, as is the case here, the "bool" is redundant.)

Unless, of course, either F or T has side effects. For a side-effect
free expression, you can use (C and [T] or [F])[0] or one of the many
other ternary operator substitutes. (Search for PEP 308.)

Dan Bishop, Jan 9, 2005
7. ### It's meGuest

> z = [i + (2, -2)[i % 2] for i in range(10)]

But then why would you want to use such feature? Wouldn't that make the
code much harder to understand then simply:

z=[]
for i in range(10):
if i%2:
z.append(i-2)
else:
z.append(i+2)

Or are we trying to write a book on "Puzzles in Python"?

It's me, Jan 10, 2005
8. ### Luis M. GonzalezGuest

It's me wrote:
> > z = [i + (2, -2)[i % 2] for i in range(10)]

>
> But then why would you want to use such feature? Wouldn't that make

the
> code much harder to understand then simply:
>
> z=[]
> for i in range(10):
> if i%2:
> z.append(i-2)
> else:
> z.append(i+2)
>
> Or are we trying to write a book on "Puzzles in Python"?

Once you get used to list comprehensions (and it doesn't take long),
they are a more concise and compact way to express these operations.
I think that writing 6 lines instead of 1 could be more readable of you
are a beginner, but after playing a little bit with listcomps for the
first time, you'll see they are very practical yet readable.

Luis M. Gonzalez, Jan 10, 2005
9. ### Steven BethardGuest

Luis M. Gonzalez wrote:
> It's me wrote:
>>> z = [i + (2, -2)[i % 2] for i in range(10)]

>>
>> But then why would you want to use such feature? Wouldn't that make
>> the code much harder to understand then simply:
>>
>> z=[]
>> for i in range(10):
>> if i%2:
>> z.append(i-2)
>> else:
>> z.append(i+2)
>>
>> Or are we trying to write a book on "Puzzles in Python"?

>
> Once you get used to list comprehensions (and it doesn't take long),
> they are a more concise and compact way to express these operations.

After looking the two suggestions over a couple of times, I'm still
undecided as to which one is more readable for me. The problem is not
the list comprehensions (which I love and use extensively). The problem
is the odd syntax that has to be used for an if/then/else expression in
Python. I think I would have less trouble reading something like:

z = [i + (if i % 2 then -2 else 2) for i in range(10)]

but, of course, adding a if/then/else expression to Python is unlikely
to ever happen -- see the rejected PEP 308[1].

Steve

[1] http://www.python.org/peps/pep-0308.html

Steven Bethard, Jan 10, 2005
10. ### Nick CoghlanGuest

Dan Bishop wrote:
> Luis M. Gonzalez wrote:
>
>>Hi there,
>>
>>I'd like to know if there is a way to add and else condition into a
>>list comprehension. I'm sure that I read somewhere an easy way to do
>>it, but I forgot it and now I can't find it...
>>
>>for example:
>>z=[i+2 for i in range(10) if i%2==0]
>>what if I want i [sic] to be "i-2" if i%2 is not equal to 0?

>
>
> z = [i + (2, -2)[i % 2] for i in range(10)]

For the specific case of +/- a number, (-1) ** x works, too:

z = [i + 2 * ((-1) ** i) for i in range(10)]

Not that I'm claiming it's particularly readable or anything. . . just that it
works

Cheers,
Nick.

--
Nick Coghlan | | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net

Nick Coghlan, Jan 11, 2005
11. ### AnthonyGuest

On Mon, 10 Jan 2005 09:13:17 -0700, Steven Bethard
<> wrote:
> Luis M. Gonzalez wrote:
> > It's me wrote:
> >>> z = [i + (2, -2)[i % 2] for i in range(10)]
> >>
> >> But then why would you want to use such feature? Wouldn't that make
> >> the code much harder to understand ...
> >> Or are we trying to write a book on "Puzzles in Python"?

> >
> > Once you get used to list comprehensions (and it doesn't take long),
> > they are a more concise and compact way to express these operations.

>
> After looking the two suggestions over a couple of times, I'm still
> undecided as to which one is more readable for me. The problem is not
> the list comprehensions (which I love and use extensively). The problem
> is the odd syntax that has to be used for an if/then/else expression in
> Python.

They're both pretty unreadable, IMHO. Why not just factor out the
if/then/else function like this:

..def plusMinusTwo(i):
.. if i%2 == 0:
.. return i-2
.. else:
.. return i+2
..
..z = [plusMinusTwo(i) for i in range(10)]

Then you can add whatever you like into the function.

Anthony

--
-----------------------------------------------------
HyPEraCtiVE? HeY, WhO aRE YoU cALliNg HypERaCtIve?!

-----------------------------------------------------

Anthony, Jan 11, 2005
12. ### Serhiy Storchaka1659322541Guest

Nick Coghlan wrote:

> Dan Bishop wrote:
>
>> Luis M. Gonzalez wrote:
>>
>>> Hi there,
>>>
>>> I'd like to know if there is a way to add and else condition into a
>>> list comprehension. I'm sure that I read somewhere an easy way to do
>>> it, but I forgot it and now I can't find it...
>>>
>>> for example:
>>> z=[i+2 for i in range(10) if i%2==0]
>>> what if I want i [sic] to be "i-2" if i%2 is not equal to 0?

>>
>>
>>
>> z = [i + (2, -2)[i % 2] for i in range(10)]

>
>
> For the specific case of +/- a number, (-1) ** x works, too:
>
> z = [i + 2 * ((-1) ** i) for i in range(10)]
>
> Not that I'm claiming it's particularly readable or anything. . . just
> that it works

Yet another variant:
z = [i + ( (i % 2) and -2 or 2 ) for i in range(10)]

--
Serhiy Storchaka

Serhiy Storchaka1659322541, Jan 11, 2005
13. ### Nick CoghlanGuest

Luis M. Gonzalez wrote:
> Hi there,
>
> I'd like to know if there is a way to add and else condition into a
> list comprehension. I'm sure that I read somewhere an easy way to do
> it, but I forgot it and now I can't find it...
>
> for example:
> z=[i+2 for i in range(10) if i%2==0]
> what if I want i to be "i-2" if i%2 is not equal to 0?
>

Hmm:

z = [newval(i) for i in range(10)] using:
def newval(x):
if x % 2:
return x - 2
else:
return x + 2

Just some more mental twiddling relating to the thread on statement local
namespaces.

Cheers,
Nick.

--
Nick Coghlan | | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net

Nick Coghlan, Jan 12, 2005
14. ### Steve HoldenGuest

Nick Coghlan wrote:

> Luis M. Gonzalez wrote:
>
>> Hi there,
>>
>> I'd like to know if there is a way to add and else condition into a
>> list comprehension. I'm sure that I read somewhere an easy way to do
>> it, but I forgot it and now I can't find it...
>>
>> for example:
>> z=[i+2 for i in range(10) if i%2==0]
>> what if I want i to be "i-2" if i%2 is not equal to 0?
>>

>
> Hmm:
>
> z = [newval(i) for i in range(10)] using:
> def newval(x):
> if x % 2:
> return x - 2
> else:
> return x + 2
>
> Just some more mental twiddling relating to the thread on statement
> local namespaces.
>

I presume the point of this is to avoid polluting the local namespace
with "newval". I further presume you also have plans to do something

regards
Steve
--
Steve Holden http://www.holdenweb.com/
Python Web Programming http://pydish.holdenweb.com/
Holden Web LLC +1 703 861 4237 +1 800 494 3119

Steve Holden, Jan 12, 2005
15. ### Stephen ThorneGuest

On 9 Jan 2005 12:20:40 -0800, Luis M. Gonzalez <> wrote:
> Hi there,
>
> I'd like to know if there is a way to add and else condition into a
> list comprehension. I'm sure that I read somewhere an easy way to do
> it, but I forgot it and now I can't find it...
>
> for example:
> z=[i+2 for i in range(10) if i%2==0]
> what if I want i to be "i-2" if i%2 is not equal to 0?

z = [i+2-(i%2)*4 for i in range(10)]

C'mon, who needs an 'if' statement when we have maths!

Stephen.

Stephen Thorne, Jan 12, 2005
16. ### Steven BethardGuest

Steve Holden wrote:
> Nick Coghlan wrote:
>> z = [newval(i) for i in range(10)] using:
>> def newval(x):
>> if x % 2:
>> return x - 2
>> else:
>> return x + 2
>>
>> Just some more mental twiddling relating to the thread on statement
>> local namespaces.
>>

> I presume the point of this is to avoid polluting the local namespace
> with "newval". I further presume you also have plans to do something

Well, while I'm not at all a fan of the "using" syntax, getting rid of
'i' is simple:

z = list(newval(i) for i in range(10))

=)

Steve

Steven Bethard, Jan 13, 2005
17. ### Andrey TatarinovGuest

Steve Holden wrote:
> Nick Coghlan wrote:
>
>> Luis M. Gonzalez wrote:
>>
>>> Hi there,
>>>
>>> I'd like to know if there is a way to add and else condition into a
>>> list comprehension. I'm sure that I read somewhere an easy way to do
>>> it, but I forgot it and now I can't find it...
>>>
>>> for example:
>>> z=[i+2 for i in range(10) if i%2==0]
>>> what if I want i to be "i-2" if i%2 is not equal to 0?
>>>

>>
>> Hmm:
>>
>> z = [newval(i) for i in range(10)] using:
>> def newval(x):
>> if x % 2:
>> return x - 2
>> else:
>> return x + 2
>>
>> Just some more mental twiddling relating to the thread on statement
>> local namespaces.
>>

> I presume the point of this is to avoid polluting the local namespace
> with "newval". I further presume you also have plans to do something

no, the point is in grouping definition of newval() with place where it
is used.

Andrey Tatarinov, Jan 13, 2005
18. ### Nick CoghlanGuest

Andrey Tatarinov wrote:
>> I presume the point of this is to avoid polluting the local namespace
>> with "newval". I further presume you also have plans to do something

>
> no, the point is in grouping definition of newval() with place where it
> is used.

I'd have said the point was both

But yeah, unfortunately the 'leaking list comp' problem won't be fixed in the
2.x series due to the compatibility problem. Fortunately, generator expressions
didn't inherit the issue.

Cheers,
Nick.

--
Nick Coghlan | | Brisbane, Australia
---------------------------------------------------------------
http://boredomandlaziness.skystorm.net

Nick Coghlan, Jan 13, 2005