python - Single Line Nested For Loops

11,065

Solution 1

You can transform your inner portion into a sequence of lists:

[[i * j if i % 2 else i + j for j in range(2)] if i == 3 else [i] for i in range(3,5)]

Unrolling a 2D iterable is easy in the general case:

[e for row in iterable for e in row]

Combining the two:

[e for row in [[i * j if i % 2 else i + j for j in range(2)] if i == 3 else [i] for i in range(3,5)] for e in row]

You can avoid storing intermediate lists by using generators:

[e for row in ((i * j if i % 2 else i + j for j in range(2)) if i == 3 else [i] for i in range(3,5)) for e in row]

Solution 2

What I came up with was to generate a sequence for each i, then have an enclosing comprehension flatten those into a single list:

[x for y in ((i*j if i%2 else i+j for j in range(0, 2)) if i == 3 else (i,) for i in range(3, 5)) for x in y]
# [0, 3, 4]

Obviously, this is way more complicated and difficult to read than the nested version, and probably performs more poorly.

Solution 3

Here's a hideous monstrosity that does it:

[x for i in range(3,5) for x in ([i*j if i%2 else i+j for j in range(2)] if i==3 else (i,))]

I'm trying hard to make this readable:

In [12]: result = [
    ...:     x
    ...:     for i in range(3, 5)
    ...:     for x in ((i*j if i%2 else i+j for j in range(2))
    ...:               if i ==3 else (i,))
    ...: ]

In [13]: print(result)
[0, 3, 4]

As pointed out in the comments, your looping shouldn't get this complex. You should use functions here to make your code more readable. It will also make the use of list-comprehensions less unwieldy. Your goal should not be "keep things on one line." Your goal should be "keep my code readable, maintainable, and simple, and honest". This list comprehension is none of those things.

Note, I don't expect this to perform better. It requires creating extra anonymous containers or generators\list-comprehensions (which requires creating and calling a function object underneath the hood).

Your goal in writing code shouldn't be "how do I learn to write increasingly complex list comprehensions", rather, it should be "how do I write and organize my code so I can make use of straightforward and readable list comprehensions".

Solution 4

I'd start off by trying something like the following:

[(i*j if i % 2 and i==3
  else i+j if i==3
  else i)
 for j in range(0, 2)
 for i in range(3, 5)]

Nested list comprehension syntax can get quite messy. This is the output:

[0, 4, 3, 4]

I guess you could make this into a set to remove dupes:

result = list(set(result))
# where result is the list above 

[0, 3, 4]
Share:
11,065
Trifrost master
Author by

Trifrost master

Updated on June 04, 2022

Comments

  • Trifrost master
    Trifrost master almost 2 years

    What will be python single line equivalent of below code?

    l=[]
    for i in range(3,5) :
        if i==3:
            for j in range(0,2):
                if i%2:
                    l.append(i*j)
                else:
                    l.append(i+j)
        else:
            l.append(i)
    print(l)
    

    I tried using a single line for nested loop but with only one condition like this:

    print([i*j if i%2 else i+j for i in range(3,5) for j in range(0,2)])
    

    Note: Here i want to learn how to use single line equivalent for nested loops with if else condition in both the loops. Also if it's not possible then specify why not!

    Thanks in advance :)

    • N Chauhan
      N Chauhan over 5 years
      Most code shouldn't reach this complexity. If it does though, it's better to write it as you did to preserve functionality as well as readability. List comprehensions (that's their actual name) are more suited to simpler loops and conditions.
    • WestCoastProjects
      WestCoastProjects over 5 years
      Some of us come from languages where doing this kind of thing is natural. I actually like the question. Python does make nesting more difficult than it could be .
    • N Chauhan
      N Chauhan over 5 years
      I agree, this is quite interesting, but I'd definitely have to open up my interpreter and start playing around to get the syntax perfect.
    • matanster
      matanster over 5 years
      Three levels of nesting is quite conventional, but python just doesn't have that as a priority (resorting to for comprehension may only obfuscate the code more)
  • N Chauhan
    N Chauhan over 5 years
    Turning it into a set then back to a list works, though not how reliable this method is.
  • Trifrost master
    Trifrost master over 5 years
    Haven't this increased the no. of loops and thereby increasing the time complexity of the code? Yes I understand that readability should be first priority but also i wanted to learn how to use list comprehensions with if-else block in both the loops. I mean out of curiosity wanted to know where the if statement will be placed.
  • juanpa.arrivillaga
    juanpa.arrivillaga over 5 years
    @Trifrostmaster "Haven't this increased the no. of loops and thereby increasing the time complexity of the code" no, increased loops does not imply increased complexity. That is a rule of thumb, not a logical implication. The time complexities are equivalent, (although, the actual runtime I think will favor the for-loop version over the abused list-comprehension
  • juanpa.arrivillaga
    juanpa.arrivillaga over 5 years
    @Trifrostmaster well, this is fine from an academic point of view, but you should never use this in production code. That is all I'm trying to make clear, since I feel a responsibility, because these questions are often viewed by people trying to write code for production. It's the sort of thing that would get you excoriated in a proper code review.
  • bittahProfessional
    bittahProfessional about 2 years
    This is awesome, but does it circumvent the issues people have brought up with the other answers? (Namely: performs worse than the equivalent for loop, and terribly difficult to read) (I'll say it's difficult to read but doesn't look as cursed as the other answers)
  • Mad Physicist
    Mad Physicist about 2 years
    @bittahProfessional. I'm not sure about the performance, but to be fair, the question can be rephrased as "how can I make this code worse". If you have a good working for loop that does not trivially follow the comprehension pattern, leave it alone.