Start learning free

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

Price List in Rust: zip and enumerate with format!

Practice Read the full explanation

You get a Vec of strings items and a Vec of integers prices. Return a Vec of strings with one line per item.

The price at each index belongs to the item at the same index.

A line looks like "1. apple: 3". It has the item's number, then the item, then its price.

The numbers start at 1. The lines keep the order of items.

 

Example 1:

Input: items = ["apple", "bread", "milk"], prices = [3, 2, 4]
Output: ["1. apple: 3", "2. bread: 2", "3. milk: 4"]
Explanation: The apple is first and costs 3.
The bread is second and costs 2.
The milk is third and costs 4.

Example 2:

Input: items = ["tea"], prices = [5]
Output: ["1. tea: 5"]
Explanation: One item gives one line, number 1.

Example 3:

Input: items = ["pen", "pen", "ink"], prices = [2, 3, 0]
Output: ["1. pen: 2", "2. pen: 3", "3. ink: 0"]
Explanation: The shop sells two kinds of pen.
Each one gets its own line, number and price.
The ink is free, so its price is 0.

 

Constraints:

  • items and prices have the same length.
  • They have 1 to 100 entries.
  • Each item is one word of lowercase letters.
  • Each price is a whole number from 0 to 1000.
STEP 1 OF 4
    Ctrl + Enter to check

    RUST · TUPLES, SORTING & BUILT-INS

    Price List in Rust, explained

    Problem overview

    The function price_list receives a vector of strings, items, and a vector of integers, prices, of the same length. The price at each index belongs to the item at the same index. It returns a vector with one line per item, like "1. apple: 3": the item's number, then the item, a colon and the price. Numbers start at 1 and the lines keep the order of items.

    For ["apple", "bread", "milk"] and [3, 2, 4] the answer is ["1. apple: 3", "2. bread: 2", "3. milk: 4"]. A single item, ["tea"] with [5], gives ["1. tea: 5"]. Repeated names stay separate lines, and a price may be 0.

    Approach

    Each line needs three things at once: the position, the item and its price. Walking over two vectors side by side is what zip does, and enumerate adds the position. Chaining them gives items of the form (index, (item, price)), and the loop can unpack that shape directly. The index starts at 0, so the printed number is i + 1.

    Step by step

    1. Create lines as an empty vector with Vec::new(), declared let mut because the loop will add to it.
    2. Loop over items.iter().zip(prices.iter()).enumerate() with the pattern (i, (item, price)). The outer parentheses unpack the pair that enumerate makes, and the inner ones unpack the pair that zip made.
    3. Push a line built with format!("{}. {}: {}", i + 1, item, price). format! works like println! but returns a String instead of printing.
    4. Return lines after the loop.

    The solution in Rust

    impl Solution {
        fn price_list(items: Vec<String>, prices: Vec<i32>) -> Vec<String> {
            let mut lines = Vec::new();
            for (i, (item, price)) in items.iter().zip(prices.iter()).enumerate() {
                lines.push(format!("{}. {}: {}", i + 1, item, price));
            }
            return lines;
        }
    }

    Here item and price are references, because iter() borrows. format! prints through a reference exactly as it would print the value, so no * is needed. The order of the adapters matters: zip(...).enumerate() gives (i, (item, price)), while enumerate().zip(...) would give ((i, item), price) and the pattern would not match.

    The index version

    The same lines can be built by looping over the positions and indexing both vectors:

    for i in 0..items.len() {
        lines.push(format!("{}. {}: {}", i + 1, items[i], prices[i]));
    }

    With items ["tea", "jam"] and prices [5, 0] it gives ["1. tea: 5", "2. jam: 0"]. It works, but it relies on both vectors having the same length: a shorter prices would panic with an index out of bounds. Iterators avoid that kind of slip, and Rust code usually prefers them.

    Why Vec::new works without a type

    The line let mut lines = Vec::new(); does not say what the vector holds. Rust works it out from the rest of the function: push adds a String made by format!, and the function returns Vec<String>. If nothing in the function fixed the type, the compiler would ask for an annotation.

    Following the loop

    For the first example, the loop sees these values:

    i=0 item=apple price=3
    i=1 item=bread price=2
    i=2 item=milk price=4

    Each pass adds one to i for the printed number, so the lines come out as 1, 2 and 3 in the same order as items.

    Testing

    Two of the examples give:

    ["1. apple: 3", "2. bread: 2", "3. milk: 4"]
    ["1. pen: 2", "2. pen: 3", "3. ink: 0"]

    Edge cases and common mistakes

    • Numbering from 0. Printing i instead of i + 1 would start the list at 0.
    • A wrong pattern. (i, item, price) does not match the nested shape and is a type error.
    • Different lengths. zip stops at the end of the shorter vector without an error: items ["x", "y"] zipped with three prices give two pairs. The constraints here promise equal lengths, so nothing is lost.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free