Using zip
The [zip docs](https://docs.python.org/3/library/functions.html#zip) say that `zip(*iterables, strict=False)`:
> Iterate over several iterables in parallel, producing tuples with an item from each one.
I use fastcore's `L` to show the lists.
```python
from fastcore.all import L
```
Otherwise the cell output is a `zip` object:
```python
zip(range(2))
```
```python
l1 = L(range(5))
l1
```
```python
l2 = L(range(6,11))
l2
```
## Zip the 2 Iterables Together
The most common scenario is zipping 2 same-length iterables together:
```python
L(zip(l1,l2))
```
## Zip a Long and Short Iterable Together
It stops when the shortest iterable is exhausted:
```python
L(zip(l1,l2[3:]))
```
With 1 iterable, you get an iterator of tuples:
```python
L(zip(l1))
```
With no args, you get an empty iterator:
```python
L(zip())
```
`items` gives you an iterator of tuples, each tuple being a k,v pair:
```python
d = {1: "one", 2: "two", 3: "three"}
L(d.items())
```
Destructuring and zipping that transposes the tuples:
```python
L(zip(*d.items()))
```
## Application: Zip a Dict Tree
This tree is from [Jeremy Howard's bfs tweet](https://x.com/jeremyphoward/status/1873810934608912550):
```python
tree = {1: {2: {4: {}}, 3: {5: {}, 6: {}}}}
L(tree)
```
```
1
├── 2
│ └── 4
└── 3
├── 5
└── 6
```
Breadth-first search (BFS) would traverse the tree from shallow to deep, printing each number as: `1 2 3 4 5 6`
Jeremy implemented BFS as:
```python
def bfs(q):
while q:
k,v = zip(*q)
print(*k)
q = [x for o in v for x in o.items()]
```
To use it, he calls it with the tree's items:
```python
bfs(tree.items())
```
```python
L(tree.items())
```
```python
L(zip(*tree.items()))
```
```python
L(zip(*tree.items()))[0]
```
```python
L(zip(*tree.items()))[1]
```
The `zip` in `k,v = zip(*q)` serves to separate node values from their children at each level. Let's see how:
1. First iteration:
```python
q = [(1, {2: {4: {}}, 3: {5: {}, 6: {}}})]
k,v = zip(*q) # k=(1,), v=({2: {4: {}}, 3: {5: {}, 6: {}}},)
```
2. Second iteration:
```python
q = [(2, {4: {}}), (3, {5: {}, 6: {}})]
k,v = zip(*q) # k=(2,3), v=({4: {}}, {5: {}, 6: {}})
```
3. Third iteration:
```python
q = [(4, {}), (5, {}), (6, {})]
k,v = zip(*q) # k=(4,5,6), v=({},{},{})
```
The `zip` cleanly separates values (`k`) to print from their children (`v`) needed for the next level of traversal.