Zipping identical iterables

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

Discussion Overview

The discussion revolves around the behavior of zipping identical iterables in Python, specifically when using the `iter()` function on a list. Participants explore the mechanics of unpacking iterators and the implications for the output of the `zip()` function. The conversation touches on theoretical aspects of iterables and iterators, as well as practical coding examples.

Discussion Character

  • Technical explanation
  • Debate/contested

Main Points Raised

  • One participant describes how using `zip(*it)` with `it = [iter(a)] * n` results in tuples that contain the next values from the iterable `a` for each iteration.
  • Another participant suggests that the behavior observed is due to the fact that `iter(a)` returns an iterator that updates its state with each call to `next()`.
  • A coding example is provided to illustrate converting a 1D array to a 2D array using `zip(*it)`.
  • There is a clarification that `iter(a)` returns an iterator, while `a` itself is the iterable, leading to some confusion among participants.
  • Alternatives to using `iter(a)` are proposed, such as using `[a] * n` or `itertools.tee`, which some participants argue could be more efficient.
  • Some participants affirm the correctness of the original code, noting its time complexity and space efficiency.

Areas of Agreement / Disagreement

There is disagreement regarding the distinction between iterables and iterators, with some participants asserting that `iter(a)` is an iterator and others emphasizing that `a` is the iterable. While some participants support the original approach, others suggest alternatives, indicating no consensus on the best method.

Contextual Notes

Participants express varying assumptions about the behavior of `iter()` and `zip()`, and there are unresolved discussions about the efficiency and appropriateness of different coding approaches.

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