1

I'm trying to write the following code as list comprehension

l=[]
for x in range(1,10):
    if x<5:
        for j in range(1,3):
            l.append(1)
    else:
        l.append(x**2)
print(l)

result is

[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]

I have tried

l=[]
l=[(1 for j in range(1,3)) if x<5 else x**2 for x in range(1,10)]
print(l)

but i'm not getting the correct result. Any ideas?

giulio
  • 157
  • 8
  • 2
    While list comprehensions are nice and can be very useful, sometimes they can become real messy. This case is probably one such occasion. Writing clear, readable and maintainable code should always be the primary goal (IMO). – Some programmer dude Aug 02 '19 at 10:39
  • I'm integrating a code already written with a lot of list comprehensions and i was wondering to write this part of code in the same form for homogeneity... as suggested could not be the best strategy :) – giulio Aug 02 '19 at 10:44
  • 1
    You probably can't do this with a single comprehension because the comprehension syntax [doesn't allow iterable unpacking](https://stackoverflow.com/questions/41251729/unpacking-generalizations), so you can't do: `[*(1 for j in range(1, 3)) if x < 5 else x**2 for x in range(1, 10)]`. – ForceBru Aug 02 '19 at 10:47

8 Answers8

3

Since you have different rules for different ranges of list, you can do this:

[1 for j in range(1,3) for x in range(1,5)] + [x**2 for x in range(5,10)] 

Note : never ignore code readability.

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79
2

if you want to use your code, you can just do it like:

x = sum([[1 for j in range(1,3)] if x<5 else [x**2] for x in range(1,10)], [])
print(x)

output:

[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]
ncica
  • 7,015
  • 1
  • 15
  • 37
1

In order to achieve the requested do the conditionals first and then add the range in the end. This should do the trick:

[1 if j < 5 else j**2 for j in range(1,10)]
Wobli
  • 192
  • 14
1

If you really need the x < 5 comparison:

from itertools import chain
iterable = chain.from_iterable([(1 for j in range(1,3)) if x<5 else [x**2] for x in range(1,10)])
list(iterable)
[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]

As already said, readability is preferable, so I strongly suggest you against this usage of list comprehension.

musicamante
  • 41,230
  • 6
  • 33
  • 58
1

Your code snippet should be, for performance and clarity, split into two loops:

L = []
for x in range(1, 5):
    for _ in range(1, 3):
        L.append(1)
for x in range(5, 10):
    L.append(x**2)

That is equivalent to:

L = [1]*8
for x in range(5, 10):
    L.append(x**2)

Side note: avoid the name l (see https://www.python.org/dev/peps/pep-0008/#names-to-avoid)

It's easy to turn in into a list-comprehension:

L = [1]*8 + [x**2 for x in range(5, 10)]

As a general rule of thumb, if you can bring a if...else out of a loop, do it.

jferard
  • 7,835
  • 2
  • 22
  • 35
0

Okay, this is not at all readable, but well...

l = [int(i) for i in (','.join(['1,1' if i<5 else str(i**2) for i in range(1,10)]).split(','))]
>>> l
[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]

Step-by-step explanation:

>>> ['1,1' if i<5 else str(i**2) for i in range(1,10)]
['1,1', '1,1', '1,1', '1,1', '25', '36', '49', '64', '81']
>>> (','.join(['1,1' if i<5 else str(i**2) for i in range(1,10)]))
'1,1,1,1,1,1,1,1,25,36,49,64,81'
>>> (','.join(['1,1' if i<5 else str(i**2) for i in range(1,10)]).split(','))
['1', '1', '1', '1', '1', '1', '1', '1', '25', '36', '49', '64', '81']

And finally, int() for each element in list. I am not sure if this can be achieved in a shorter line without adding two lists.

Sayandip Dutta
  • 15,602
  • 4
  • 23
  • 52
0

This should work for you,

result = add([[1 for j in range(1,3)] if x<5 else [x**2] for x in range(1,10)], [])
print(result)
[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]
Shreyash Sharma
  • 180
  • 2
  • 14
0

Actually you can do this with only list comprehensions without sum or other tricks. However, a little warning - never use the following code in your codebase

>>> [1 if x<5 else x**2 for x in range(1, 10) for y in range(2 if x<5 else 1)]
[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]

UPD:

If you want to really confuse someone, you can do this -

>>> [x**(2*(not x<5)) for x in range(1, 10) for y in range((x<5)+1)]
[1, 1, 1, 1, 1, 1, 1, 1, 25, 36, 49, 64, 81]

Alexandr Zayets
  • 299
  • 1
  • 8