How to understand n-length groups idiom zip(*[iter(s)]*n)

Hi forum,

I have trouble understanding this n-length groups idiom

>>> s = [1, 2, 3, 4, 5, 6]
>>> list( zip( *[ iter( s ) ] *2 ) )
[(1, 2), (3, 4), (5, 6)]
>>> 

Could you please teach me. Thanks in advance.

Does the whole expression evaluate in this order?

Step 1: iter(s)
It’s a iterator on a sequence.

Step 2: [ iter(s) ] *2
It’s a list repetition. Two iterators on the sequence. Take two value from the sequence one time. There’re two stream of iterator:
s1: [1, 3, 5]
s2: [2, 4, 6]

Step 3: *[ iter(s) ] *2
I do not understand the first * star operator. Is it unzip or unpack operator? Or are unzip and unpack the same thing? What does it do here?

Step 4: zip( *[ iter(s) ] *2)
s1: [1, 3, 5]
s2: [2, 4, 6]

So it’s equal to:
zip(s1, s2)

(1, 2), (3, 4), (5, 6)

Step 5: list( zip( * [ iter(s) ] *2 ) )
Constructs a list to show the zip result
[(1, 2), (3, 4), (5, 6)]

I wouldn’t phrase it that way. iter(s) returns an iterator object. [iter(s) *2] creates a list with that object duplicated. It’s not that there’s 2 streams, there’s just one object. The sequence that comes from that object depends on how it’s read.

>>> [iter(s)] *2
[<list_iterator object at 0x1059d36a0>, <list_iterator object at 0x1059d36a0>]

One list with a duplicated object in the first two positions.

Then the first star unpacks the object.
zip([....]) passes a list to zip as the only argument
zip(*[....]) passes each element of the list to zip as separate arguments. So

zip(*[iter(s)] * 2) is equivalent to:
i = iter(s) ; zip(i, i)

1 Like

Is it in the form of a nested list:
[ [1,3,5], [2,4,6] ]

Thanks!

No, the iterator object inside isn’t examined until later. It’s a list with two object in it. Identical to what I showed earlier:

>>> [iter(s)] *2
[<list_iterator object at 0x1059d36a0>, <list_iterator object at 0x1059d36a0>]

Semantically, you can think of it similar to nested lists (and zip() would behave the same way as if you did pass in nested lists)

1 Like

The critical thing about the iterator is that since it’s the same iterator, it’ll only produce the value once. So each iteration, zip() calls next() on it twice, giving two objects.

1 Like