Nugget 12
Home
map() and filter() get all the attention, but the
iterator toolbox has far more — for slicing, combining, pairing, reversing,
and stepping through sequences with precision.
take() and skip()
take(n) yields the first n items and stops.
skip(n) ignores the first n items and yields the rest:
let nums = 1..=10; // take — first 3 items let first_three: Vec<_> = nums.clone().take(3).collect(); assert_eq!(first_three, vec![1, 2, 3]); // skip — everything after the first 7 let after_seven: Vec<_> = nums.clone().skip(7).collect(); assert_eq!(after_seven, vec![8, 9, 10]); // combined: pagination let page: Vec<_> = nums.clone().skip(4).take(3).collect(); assert_eq!(page, vec![5, 6, 7]); // skip 4 items → start at 5, take 3 → 5, 6, 7
💡 Safe on short iterators
take(100) on a 5-item iterator just yields all 5 — no panic.
skip(100) on a 5-item iterator yields nothing — also no panic.
enumerate()
enumerate() pairs each item with its index (starting at 0).
This is the iterator-friendly replacement for C-style index loops:
let fruits = ["apple", "banana", "cherry"];
for (i, fruit) in fruits.iter().enumerate() {
println!("#{i}: {fruit}");
}
// #0: apple
// #1: banana
// #2: cherry
// With filter
let fruits = ["apple", "avocado", "banana", "apricot", "cherry"];
for (i, fruit) in fruits.iter()
.enumerate()
.filter(|(_, name)| name.starts_with("a"))
{
println!("fruit starting with 'a' at index {i}");
}
// fruit starting with 'a' at index 0
// fruit starting with 'a' at index 1
// fruit starting with 'a' at index 3
📐 enumerate() captures position
Note: enumerate() records the index before any
subsequent filter() — so the index matches the original
position, not the filtered position. If you put enumerate after
filter, indices reset.
zip()
zip() combines two iterators into one, producing a tuple of items
side-by-side. It stops when either iterator runs out:
let names = ["Alice", "Bob", "Charlie"];
let scores = [95, 87, 92];
let paired: Vec<(&str, &i32)> = names.iter()
.zip(scores.iter())
.collect();
// [("Alice", 95), ("Bob", 87), ("Charlie", 92)]
// Uneven lengths — stops at the shorter
let short = [1, 2];
let long = [10, 20, 30, 40];
let zipped: Vec<_> = short.iter().zip(long.iter()).collect();
assert_eq!(zipped, vec![(&1, &10), (&2, &20)]); // 30 and 40 dropped
A common pattern: zip with enumerate and the source
to create a HashMap:
use std::collections::HashMap;
let keys = ["x", "y", "z"];
let values = [10, 20, 30];
let map: HashMap<&str, &i32> = keys.iter()
.zip(values.iter())
.collect();
// {"x": 10, "y": 20, "z": 30}
chain()
chain() appends one iterator after another:
let first = [1, 2, 3];
let second = [4, 5, 6];
let combined: Vec<_> = first.iter()
.chain(second.iter())
.collect();
// [1, 2, 3, 4, 5, 6]
// Chaining more than two
let a = [1, 2];
let b = [3, 4];
let c = [5, 6];
let all: Vec<_> = a.iter()
.chain(b.iter())
.chain(c.iter())
.collect();
// [1, 2, 3, 4, 5, 6]
// step_by — every nth element
let evens: Vec<_> = (0..=10).step_by(2).collect();
assert_eq!(evens, vec![0, 2, 4, 6, 8, 10]);
// rev — reverse (needs a double-ended iterator)
let backwards: Vec<_> = (1..=5).rev().collect();
assert_eq!(backwards, vec![5, 4, 3, 2, 1]);
// Practical: read lines reversed
let text = "first\nsecond\nthird";
for line in text.lines().rev() {
println!("{line}");
}
// third
// second
// first
The real power comes from combining adapters. Here's a "leaderboard" that sorts scores, skips the bottom 3, and prints the top entries with ranks:
use std::collections::HashMap;
let scores = HashMap::from([
("Alice", 95),
("Bob", 72),
("Charlie", 88),
("Diana", 91),
("Eve", 67),
]);
// Top 3, ranked
let mut ranked: Vec<(&str, &i32)> = scores.iter().collect();
ranked.sort_by(|a, b| b.1.cmp(a.1)); // sort by score descending
// Now with iterators:
ranked.iter()
.take(3)
.enumerate()
.for_each(|(i, (name, score))| {
println!("#{}: {} — {}", i + 1, name, score);
});
// #1: Alice — 95
// #2: Diana — 91
// #3: Charlie — 88
take(n) / skip(n) — slice an iterator like array slicing.enumerate() — pair items with their index (replaces C-style index loops).zip() — combine two iterators pairwise, like a zipper.chain() — concatenate iterators end-to-end.step_by(n) — every nth element; rev() — reverse the order.