Skip to content

Combining Iterators

zip combines two iterators into [a, b] pairs, stopping at the shorter one. It is useful for processing parallel series — names with ages, indices with values, etc. chain concatenates them in sequence, without creating an intermediate array:

zip with equal and different lengths; chain of ranges and prefix/suffix.

07-iter-zip-chain.zolo
Playground
// Feature: `Iter.zip` and `Iter.chain`

// Syntax: `a.zip(b)` pairs them; `a.chain(b)` concatenates.

// When to use: combine two parallel series (zip) or stitch two

// sequences into one (chain).


use std::Iter

// zip — stops at the shorter one.

let names = Iter::from(["Alice", "Bob", "Charlie"])
let ages = Iter::from([30, 25, 35])
let pairs = names.zip(ages)
print(pairs.collect())

// expected: [["Alice", 30], ["Bob", 25], ["Charlie", 35]]


// zip with different sizes — output has the size of the shorter one.

let a = Iter::from([1, 2, 3, 4, 5])
let b = Iter::from(["x", "y"])
let mixed = a.zip(b)
print(mixed.collect())

// expected: [[1, "x"], [2, "y"]]


// chain — first a, then b.

let part1 = Iter::range(1, 4)
let part2 = Iter::range(7, 10)
let combined = part1.chain(part2)
print(combined.collect())

// expected: [1, 2, 3, 7, 8, 9]


// chain is useful to insert a prefix/suffix.

let body = Iter::from([10, 20, 30])
let header = Iter::from([0])
let with_header = header.chain(body)
print(with_header.collect())
// expected: [0, 10, 20, 30]

Every lazy pipeline needs a terminal consumer to execute. collect() materializes the result into an array; each(fn) iterates over the elements executing only effects, without producing an array:

collect after map; each for line-by-line logging; counter via closure with each.

08-iter-collect-each.zolo
Playground
// Feature: `Iter.collect` and `Iter.each`

// Syntax: `it.collect()` materializes into an array; `it.each(fn)`

// runs an effect per element (without producing an array).

// When to use: collect when you need the result; each when you only

// want a side effect per item.


use std::Iter

// collect — produces an array.

let arr = Iter::range(1, 4).map(|x| x * 10).collect()
print(arr)

// expected: [10, 20, 30]


// each — effect only, return is nil.

print("listing:")
Iter::range(1, 4).each(|x| print("  item {x}"))

// expected:

//   listing:

//     item 1

//     item 2

//     item 3


// Combining: count how many were consumed via closure.

var count = 0
Iter::range(1, 11).filter(|x| x % 3 == 0).each(|_| {
  count += 1
})
print("multiples of 3 in 1..10 = {count}")
// expected: multiples of 3 in 1..10 = 3

Remember: Iter.* is lazy — if you do not call collect, each, or fold, no element will be processed.

enespt-br