Zipping identical iterables

  • Python
  • Thread starter ergospherical
  • Start date
  • #1
ergospherical
1,045
1,335
Let a be a list (say a = [0,1,2,3,...]), then construct a list of n iterables iter(a),
Python:
it = [iter(a)] * n
When I go to unzip this, e.g.
Python:
for x in zip(*it):
Then x is (0,1,...,n-1), then (n,n+1,...,2n-1), etc.
Just trying to iron out why this works. Because schematically, *it is unpacking it into

*it = iter(a), iter(a), ..., iter(a)

And then zip(*it) should be joining together the first values of each of those n iterables, then the second, etc.

I assume it's because each time iter(a) is seen in zip, the iterable value is updated?
Otherwise x would be (0,0,...,0), then (1,1,...,1) etc.?
 
Technology news on Phys.org
  • #2
ergospherical said:
I assume it's because each time iter(a) is seen in zip, the iterable value is updated?
Iter(a) is a function that returns the next value from the iterable. Each next value will only be returned once from a given iterable.

What you want for what it looks like you are trying to do in the OP is itertools.tee. At least, if you insist on doing it using iterators, instead of just doing it = ([list(a)] * n). Or even just it = [a] * n if you aren't going to mutate a itself anywhere.
 
  • #3
iter(a)is the iterable, not a . E.g. look at the following implementation of converting a 1d array a to a m by n 2d array,

Python:
def to_2d_array(a: List[int], m: int, n: int) -> List[List[int]]:
        if m*n != len(a):
            return []
        ans = []
        it = [iter(a)] * n
        for row in zip(*it):
            ans.append(row)
        return ans

zip(*it) is the new iterable built by unpacking itand then calling zip
 
  • #4
ergospherical said:
iter(a)is the iterable
No, iter(a) returns an iterator, not an iterable. a itself is the iterable.

I strongly suggest that you try the alternatives I gave.
 
  • #5
The code itself is fine, and quite good (O(m*n) time and O(1) extra space)
 
  • #6
ergospherical said:
iter(a)is the iterable, not a .
As I've already said, a itself is an iterable. Calling iter on it returns an iterator (as you can easily see by inspecting its type in the REPL). The iterator also works like an iterable if you call other functions on it that take iterables as arguments, as you are doing. But [a] itself would work just as well, since the actual iteration is done implicitly by the for loop, and that loop is over the zip return value, which treats iter(a) exactly the same as a itself.

ergospherical said:
The code itself is fine, and quite good (O(m*n) time and O(1) extra space)
The alternative I suggested, using just [a] instead of [iter(a)], will run in the same big-O time (since that's unavoidable) and will use even less extra space, since you are not constructing an unnecessary extra iterator over [a].
 

Similar threads

Back
Top