Python 2 weird list comprehension behavior

I looked around understanding the list and saw something strange. Code:

a = ['a', 'a', 'a', 'b', 'd', 'd', 'c', 'c', 'c'] print [(len(list(g)), k) if len(list(g)) > 1 else k for k, g in groupby(a)] 

Result:

[(0, 'a'), 'b', (0, 'd'), (0, 'c')]

But I wanted to see:

[(3, 'a'), 'b', (2, 'd'), (3, 'c')]

What is the reason for this behavior?

+6
source share
2 answers

When you call list() on the itertools._grouper object, you exhaust the object. Since you do this twice, the second instance results in a length of 0.

Firstly:

 if len(list(g)) 

now it’s exhausted. Then:

 (len(list(g)), k)) 

It will have a length of 0.

You can set the generator / understanding in your understanding of list to exhaust the object and save the relevant data before processing it:

 >>> [(y,x) if y>1 else x for x,y in ((k, len(list(g))) for k, g in groupby(a))] [(3, 'a'), 'b', (2, 'd'), (3, 'c')] 
+12
source

You need to make sure that g elements are consumed only once:

 >>> print [(len(list(g)), k) if len(list(g)) > 1 else k for k, g in ((k, list(g)) for k, g in groupby(a))] [(3, 'a'), 'b', (2, 'd'), (3, 'c')] 

This code will also k, g in groupby(a) over k, g in groupby(a) , but it will turn g into a list object. The rest of the code can access g as many times as necessary (to check the length) without consuming the results.

Before making this change, g was an itertools._grouper object, which means you can iterate over g only once. After that, it will be empty, and you cannot repeat it again. This is why you see a length of 0 in the results.

+4
source

All Articles