'How to transform loop below in list comprehension?

Is it possible to transform loop below in list comprehension? I know this way is more readable, but anyway just wondering..

new_dict = {"Water Lilly": "flower",
               "Swifts": "bird",
               "Callery Pear": "tree",
               "Swallows": "bird",
               "Dahlia": "flower",
               "Tulip": "flower",}

for key, value in new_dict.items():
    print(key+':')
    for val in value:
        print("-" + val)


Solution 1:[1]

I think this would work but kinda hard to read :D

x = [(print(key + ":"), [print("-" + val) for val in value]) for key, value in new_dict.items()]

It works like a normal listcomprehension

[do_sth_with_x(x) for x in list]

but your working 2 values

[(do_sth_with_x(x), do_sth_with_y(y)) for x, y in list]

and in the 3th step you add a second list comprehension instead of the do_st_with_y()

there you go there is your listcomp

Solution 2:[2]

It can be done with a one-liner as suggested in this answer. We can agree that the one liner is hard to read. Another issue with it is that we are using side-effects in the comprehension, which is generally considered a bad practice as well.

List comprehensions are expressions; something that evaluates to a value. As opposed to statements, something that is an imperative directive to the interpreter. print(..) statements are, well, statements. Take a look at this SO question to learn about the differences.

Purely as an exercise of converting a nested for loop into list comprehension, we can try and tackle this problem from the inside out.

let's start with a simple example.

for i in list1:
   do_something(i)

can be converted to [do_something(i) for i in list1]

but if we have multiple statements, how do we get all of them to execute?

for i in list1:
   do_something(i)
   do_something_else(i)

we can use a "trick" of python where a tuple is evaluated in order whenever python encounters it.

[(do_something(i), do_something_else(i)) for i in list1]

for key, value in new_dict.items():
    do_outer(key)
    for val in value:
        do_inner(value)

converting the inner loop to List comprehension looks like this

for key, value in new_dict.items():
    do_outer(key)
    [do_inner(value) for value in value]

next we can try to convert the outer loop

[(inner loop stuff) for key, value in new_dict.items()]

expanding the inner loop stuff

[(do_outer(key), [do_inner(value) for value in value]) for
                      key, value in new_dict.items()]

We use the tuple trick to club both do_outer and the inner comprehension inside the outer comprehension.

I think we can all agree that the for loop is simpler to read and understand, and looking at the list comprehension, we have no idea what kind of crazy side-effects do_inner and do_outer may cause.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 srj