Start learning free

LESSON 277 OF 679 · TUPLES, SORTING & BUILT-INS

Enumerate and Zip in Rust: Looping with Indexes and Pairs

Lesson Read the full explanation

TL ; DR:

enumerate() counts the items while you loop. zip() walks two vectors side by side.


let fruits = vec!["apple", "kiwi", "plum"];

let prices = vec![3, 1, 2];

for (i, fruit) in fruits.iter().enumerate() {
    println!("{}. {}", i + 1, fruit);
}

// prints 1. apple, 2. kiwi, 3. plum

for (fruit, price) in fruits.iter().zip(prices.iter()) {
    println!("{} {}", fruit, price);
}

// prints apple 3, kiwi 1, plum 2


Full lesson:

You have looped with for i in 0..meals.len(). Then meals[i] gave the item. As Vec & Iterators said, Rust prefers iterators. They give you both at once.

enumerate() gives each item together with its index. The loop unpacks the tuple into two names, as let (name, age) = pet does.

for (i, meal) in meals.iter().enumerate() {
    println!("{} {}", i, meal);
}

The index comes first. It starts at 0, so print i + 1 for a numbered list. The index is a usize.

a.iter().zip(b.iter()) walks two vectors side by side. It pairs the first item of a with the first item of b. Then it pairs the second items, and so on. Each pair is a tuple.

for (fruit, price) in fruits.iter().zip(prices.iter()) {
    println!("{} costs {}", fruit, price);
}

The items are references, because iter() borrows them. println! prints them as they are. For math, write *price.

zip stops at the end of the shorter vector. The extra items are skipped, with no error.

The two work together. Zip first, then call enumerate() on the result. Each item is then an index and a pair, so the names nest.

let pairs = fruits.iter().zip(prices.iter());
for (i, (fruit, price)) in pairs.enumerate() {
    println!("{}. {} costs {}", i + 1, fruit, price);
}

The two lines can also be one: for (i, (fruit, price)) in fruits.iter().zip(prices.iter()).enumerate().


Your task

A quiz show keeps its players in the vector players. Their points are in scores, in the same order.

First, print the players as a numbered list from 1, like 1. Ana. Use enumerate().

Then print each player with their points, like Ana has 12 points. Use zip().

Expected output:

1. Ana
2. Ben
3. Cleo
Ana has 12 points
Ben has 9 points
Cleo has 15 points
STEP 1 OF 4
    Ctrl + Enter to check

    RUST · TUPLES, SORTING & BUILT-INS

    Enumerate And Zip in Rust, explained

    Why not index by hand

    A loop such as for i in 0..meals.len() with meals[i] inside works, but Rust prefers iterators, which give you both the position and the item at once with no way to run past the end. Two adapters cover the common cases: enumerate() counts the items while you loop, and zip() walks two vectors side by side.

    enumerate: items with their index

    enumerate() gives each item together with its index, as a tuple. The loop unpacks the tuple into two names, the way let (name, age) = pet does.

    let fruits = vec!["apple", "kiwi", "plum"];
    
    for (i, fruit) in fruits.iter().enumerate() {
        println!("{}. {}", i + 1, fruit);
    }
    1. apple
    2. kiwi
    3. plum

    The index comes first and starts at 0, so print i + 1 for a numbered list. The index is a usize.

    zip: two vectors side by side

    a.iter().zip(b.iter()) pairs the first item of a with the first item of b, then the second items, and so on. Each pair is a tuple.

    let prices = vec![3, 1, 2];
    
    for (fruit, price) in fruits.iter().zip(prices.iter()) {
        println!("{} {}", fruit, price);
    }
    apple 3
    kiwi 1
    plum 2

    The items are references, because iter() borrows. println! prints them as they are; for arithmetic, write *price.

    zip stops at the end of the shorter vector, and the extra items are skipped with no error. Zipping three players with two numbers gives two pairs.

    Using both together

    To number the pairs, call enumerate() on the zipped iterator. Each item is then an index and a pair, so the names nest in the same shape:

    for (i, (fruit, price)) in fruits.iter().zip(prices.iter()).enumerate() {
        println!("{}. {} costs {}", i + 1, fruit, price);
    }
    1. apple costs 3
    2. kiwi costs 1
    3. plum costs 2

    The order of the calls decides the shape. zip(...).enumerate() gives (i, (a, b)).

    Other things to loop over

    enumerate() works on any iterator, not only on vectors. On the characters of a string, "abc".chars().enumerate() gives (0, 'a'), (1, 'b') and (2, 'c').

    A pair of values also invites a calculation. Zipping two vectors and multiplying the pairs gives a dot product: with [1, 2, 3] and [4, 5, 6], the expression a.iter().zip(b.iter()).map(|(x, y)| x * y).sum::<i32>() is 32. The closure unpacks each pair right in its parameter list, with the same pattern a for loop uses.

    Common mistakes

    • Index second. The pattern is (i, item). Writing (item, i) puts the item in the index's place and the compiler reports a type problem when you use them.
    • Starting the count at 0 in a numbered list. Print i + 1, as above.
    • Forgetting the nesting. After zip(...).enumerate(), the pattern (i, fruit, price) does not match; it must be (i, (fruit, price)).
    • Expecting an error from zip on uneven lengths. It quietly stops at the shorter one, so a missing score would drop a player from the output without a warning.

    The exercise, step by step

    A quiz show keeps its players in players and their points in scores, in the same order. The task prints the players as a numbered list, then each player with their points.

    1. First loop: for (i, player) in players.iter().enumerate(). The index comes first.
    2. Print i + 1, a dot, a space and the player, such as 1. Ana. The index starts at 0, so adding 1 makes Ana number 1.
    3. Second loop: for (player, points) in players.iter().zip(scores.iter()), which pairs Ana with 12, Ben with 9 and Cleo with 15.
    4. Print each player, the word has, the points and the word points. No index is needed here.
    fn main_function() {
        let players = vec!["Ana", "Ben", "Cleo"];
        let scores = vec![12, 9, 15];
    
        for (i, player) in players.iter().enumerate() {
            println!("{}. {}", i + 1, player);
        }
    
        for (player, points) in players.iter().zip(scores.iter()) {
            println!("{} has {} points", player, points);
        }
    }

    The output:

    1. Ana
    2. Ben
    3. Cleo
    Ana has 12 points
    Ben has 9 points
    Cleo has 15 points

    Key takeaways

    • enumerate() yields (index, item), with the index first, starting at 0.
    • zip() yields pairs of items by position and stops at the shorter vector.
    • Together, zip(...).enumerate() yields (index, (a, b)), so unpack it with nested parentheses.
    • With iter() the items are references; use * for arithmetic.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free