1

I knew list comprehension but I am having a hard time to understand how and why the list comprehension works below and I did not find similar post. Could someone please break it down and explain a bit more about it?

test_list1 = [1, 4, 5, 6, 5]
test_list2 = [3, 5, 7, 2, 5]
  
# using list comprehension to concatenate 2 lists
res_list = [y for x in [test_list1, test_list2] for y in x]

Thank you.

Jason T.
  • 113
  • 1
  • 2
  • 7
  • for each list `x` in the list of lists, take each element `y` and put it in the final list – mozway Apr 14 '22 at 08:19
  • It works as others explained, but it's a weird way to concatenate two lists. You can just use the `+` operator, or `list.extend()`. – Jussi Nurminen Apr 14 '22 at 08:20
  • @Jussi it can be useful if you want to make an iterator, it's potentially also more efficient when there are many lists to concatenate – mozway Apr 14 '22 at 08:21
  • 1
    Any [question](https://stackoverflow.com/a/71868546/4194079) @Jason ? – keepAlive Apr 15 '22 at 08:08
  • 1
    @keepAlive No. I have read through your answer and that link of "nested list-comprehension" really helped me to understand the concept behind it. Thank you very much for the help! – Jason T. Apr 16 '22 at 07:43

1 Answers1

3

Because

res_list = [y for x in [test_list1, test_list2] for y in x]

which is a nested list-comprehension, is equivalent to

res_list = []
for x in [test_list1, test_list2]:
    for y in x:
        res_list.append(y)

If what you really want to do is concatenation, you could just do

res_list = test_list1 + test_list2

or using sum()

res_list = sum([test_list1, test_list2], [])

or using itertools.chain.from_iterable

import itertools
[*res_list] = itertools.chain.from_iterable([test_list1, test_list2])

or usingas explained in comment (and reported here for desirable completeness)list.extend

res_list = []
for x in [test_list1, test_list2]:
    res_list.extend(x)
keepAlive
  • 6,369
  • 5
  • 24
  • 39
  • `sum` looks fancy but it a really bad idea, performance is terrible for many sublists. Compare `[y for x in l for y in x]` and `sum(l, start=[])` for `l = [['a', 'b', 'c'] for i in range(1000)]`: `73.7 µs ± 418 ns` vs `1.82 ms ± 13.9 µs` – mozway Apr 14 '22 at 08:26
  • Actually, for small lists (of sublists), it is more performant than `itertools.chain.from_iterable` for example. What about, say, `range(10)` @mozway ? – keepAlive Apr 14 '22 at 08:27
  • See my example above, 44x slower for 1000 sublists, and it gets worse when there are more. If you just have a few, use `l1+l2+l3` it's more explicit, performance won't matter when you're sparing once a few ns ;) – mozway Apr 14 '22 at 08:29
  • I often deal, repeatedly, with small lists (of sublists) of variable length and I cannot *hard-writtenly* do `... + ... + ...`. Moreover, having `start=[]` makes things clear. – keepAlive Apr 14 '22 at 08:31
  • I guess what matters is that the code it explicit and you ensure that your `sum(...)` won't be left unchanged and have a large list as input in the future ;) – mozway Apr 14 '22 at 08:33
  • 1
    @mozway True ! And *Special cases aren't special enough to break the rules* are they ? just kidding. – keepAlive Apr 14 '22 at 08:34