Start learning free

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

Oldest Pet in Rust: Scanning a Vector of Tuples

Practice Read the full explanation

You get a Vec of pets, pets. Each pet is a pair: its name and its age, like ("Rex", 4).

Return the name of the oldest pet.

Several pets may share the oldest age. Then return the one that comes first in pets.

The starter code shows how your language holds a pair.

 

Example 1:

Input: pets = [("Rex", 4), ("Bella", 7), ("Max", 2)]
Output: "Bella"
Explanation: Bella is 7.
Rex and Max are younger.

Example 2:

Input: pets = [("Luna", 3), ("Coco", 9), ("Milo", 9)]
Output: "Coco"
Explanation: Coco and Milo are both 9.
Coco comes first in the list.

Example 3:

Input: pets = [("Kiki", 0)]
Output: "Kiki"
Explanation: Kiki is the only pet.

 

Constraints:

  • pets has at least one pet.
  • Every age is a whole number from 0 to 30.
  • Each name is a capital letter followed by lowercase letters, like "Rex".
STEP 1 OF 5
    Ctrl + Enter to check

    RUST · TUPLES, SORTING & BUILT-INS

    Oldest Pet in Rust, explained

    Problem overview

    The function oldest_pet receives a vector pets. Each pet is a tuple (String, i32): its name and its age. It returns the name of the oldest pet. When several pets share the oldest age, the one that comes first in the vector wins.

    For [("Rex", 4), ("Bella", 7), ("Max", 2)] the answer is "Bella". For [("Luna", 3), ("Coco", 9), ("Milo", 9)] it is "Coco", because Coco and Milo are both 9 and Coco is listed first. A single pet, [("Kiki", 0)], gives "Kiki".

    Approach

    Go through the pets once and remember the oldest one seen so far. Before the loop sees anything, the first pet is the best candidate. Each later pet replaces it only if it is strictly older. The word strictly handles ties: a pet with the same age as the current best does not replace it, so the earlier pet stays.

    Step by step

    1. Start with a reference to the first pet. let mut oldest = &pets[0]; borrows the pet instead of moving it out of the vector, and mut lets oldest point at a different pet later.
    2. Loop over &pets with the loop variable pet, another reference to a tuple.
    3. Compare ages. A pet's age is its .1, so the test is pet.1 > oldest.1, with a strict greater-than.
    4. Move the marker. Inside the if, oldest = pet;. Both sides are references, so nothing is copied; oldest just points at this pet.
    5. Return the name. oldest.0.clone() makes a new String for the return value. The name in the vector stays where it is, because oldest only borrows it.

    The solution in Rust

    impl Solution {
        fn oldest_pet(pets: Vec<(String, i32)>) -> String {
            let mut oldest = &pets[0];
            for pet in &pets {
                if pet.1 > oldest.1 {
                    oldest = pet;
                }
            }
            return oldest.0.clone();
        }
    }

    Two Rust details are worth noticing. The reference oldest may not outlive pets, and it doesn't, because both live until the function ends. And the function must clone() the name: it can't return a reference to data that is dropped when pets goes out of scope.

    Following the loop

    For [("Luna", 3), ("Coco", 9), ("Milo", 9)], oldest points at these pets as the loop moves on:

    petoldest after the check
    LunaLuna
    CocoCoco
    MiloCoco

    Milo is 9, the same as Coco, so the strict test fails and Coco stays.

    Another way, and a trap

    An iterator method looks like a shortcut: pets.iter().max_by_key(|p| p.1) finds the pet with the largest age. But when several items share the largest key, max_by_key returns the last of them. On the second example it gives "Milo", not "Coco", so it breaks the tie rule of this lesson. The explicit loop with a strict comparison keeps the first.

    Testing

    On the three examples the function returns:

    Bella
    Coco
    Kiki

    Edge cases and common mistakes

    • Using >=. It would let the later pet win a tie, so the second example would return "Milo".
    • Starting with age 0 and no pet. An age can be 0, as with Kiki, so a made-up starting age would need a name too. Starting from the first real pet avoids that.
    • Returning oldest.0 without clone(). That tries to move a String out of a borrowed tuple, which the compiler rejects.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free