Zipping identical iterables

  • Context: Python 
  • Thread starter Thread starter ergospherical
  • Start date Start date
Click For Summary
SUMMARY

The discussion centers on the behavior of the Python function zip(*it) when it is constructed as a list of identical iterators from a single iterable a. The key insight is that each call to iter(a) generates a new iterator, allowing zip(*it) to produce distinct tuples for each iteration. The suggested alternative is to use itertools.tee for creating multiple independent iterators, or simply to use [a] * n to avoid unnecessary iterator creation. The performance of the original code is confirmed to be O(m*n) time complexity with O(1) extra space.

PREREQUISITES
  • Understanding of Python iterables and iterators
  • Familiarity with the zip function in Python
  • Knowledge of the itertools module
  • Basic understanding of time and space complexity analysis
NEXT STEPS
  • Learn about itertools.tee for creating multiple independent iterators
  • Explore the differences between iterables and iterators in Python
  • Investigate the performance implications of using zip with iterators
  • Study the implementation of 2D arrays in Python using list comprehensions
USEFUL FOR

Python developers, data scientists, and anyone interested in optimizing iterable handling and performance in Python programming.

ergospherical
Science Advisor
Homework Helper
Education Advisor
Insights Author
Messages
1,100
Reaction score
1,387
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
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.
 
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
 
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.
 
The code itself is fine, and quite good (O(m*n) time and O(1) extra space)
 
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

  • · Replies 16 ·
Replies
16
Views
3K
  • · Replies 0 ·
Replies
0
Views
2K
  • · Replies 7 ·
Replies
7
Views
5K
  • · Replies 12 ·
Replies
12
Views
2K
  • · Replies 6 ·
Replies
6
Views
2K
Replies
3
Views
2K
  • · Replies 7 ·
Replies
7
Views
3K
  • · Replies 2 ·
Replies
2
Views
2K
Replies
1
Views
2K
Replies
3
Views
2K