Start learning free

LESSON 186 OF 414 · LOOPS - CHALLENGES

Get Full Names 2 in Rust: step_by and format!

Practice Read the full explanation

Given an array of strings names that contain first and last names adjacent to each other, return an array containing the full names (separated by one space)

Example:

Input:  names = ["John", "Doe", "Andy", "Smith", "Mary", "Johnson"]

Output:  ["John Doe", "Andy Smith", "Mary Johnson"]
STEP 1 OF 5
    Ctrl + Enter to check

    RUST · LOOPS - CHALLENGES

    Get Full Names 2 in Rust, explained

    Problem overview

    The function get_full_names_2 receives a Vec<String> called names. The vector lists people's names in pairs: a first name, then the matching last name, then the next person's first name, and so on. The function must return a new Vec<String> with one full name per pair, written as the first name, one space, and the last name.

    For ["John", "Doe", "Andy", "Smith", "Mary", "Johnson"] the result is ["John Doe", "Andy Smith", "Mary Johnson"]. Six strings go in and three come out, because every two neighbouring strings merge into one.

    Approach: visit the even indices

    First names always sit at the even positions 0, 2, 4, and so on, and each last name sits right after its first name, at the next odd position. So the task is to look at the positions 0, 2, 4, ... and, at each one, combine the string there with the string after it.

    A loop that visits every index and skips the odd ones would work, but Rust has a cleaner tool: take the range of all indices, 0..names.len(), and ask it to move two at a time with step_by(2). The loop variable then lands only on first names, and index + 1 is always the partner.

    Step by step

    1. Create an empty vector named answer. It must be declared with let mut, because pushing into it changes it. You don't write its element type: the compiler sees that you later push String values and fills it in.
    2. Loop over the even indices. The range 0..names.len() covers every valid index, and step_by(2) keeps every second one. The range is wrapped in parentheses so the method call applies to the whole range.
    3. Build the full name with the format! macro. It works like println!, but instead of printing it returns a new String. Each {} is replaced by the next argument, so "{} {}" puts a single space between the two parts.
    4. Push the full name onto answer. Pushing adds to the end, so the full names come out in the same order as the pairs went in.
    5. Return answer after the loop, not inside it. A return inside the loop would end the function after the first pair.

    The solution in Rust

    impl Solution {
        fn get_full_names_2(names: Vec<String>) -> Vec<String> {
            let mut answer = Vec::new();
            for index in (0..names.len()).step_by(2) {
                let name = format!("{} {}", names[index], names[index + 1]);
                answer.push(name);
            }
            return answer;
        }
    }
    

    Rust details worth knowing:

    • The index type is usize. names.len() returns a usize, so the range, and therefore index, is a usize too. That is the type Rust requires for indexing a vector, so no conversion is needed.
    • format! borrows its arguments. Writing names[index] inside the macro doesn't move the string out of the vector. The macro only reads it, so names stays intact, and the result is a brand-new String that owns its own text.
    • Type inference. Vec::new() alone doesn't say what the vector holds. Because answer.push(name) passes a String and the function returns Vec<String>, the compiler concludes that answer is a Vec<String>.
    • Half-open ranges. 0..6 contains 0 through 5. With step_by(2) it yields 0, 2 and 4. For a length of 7 it would yield 0, 2, 4 and 6.
    • return at the end. The final return answer; is correct. Idiomatic Rust often writes just answer as the last expression, without a semicolon; both return the same value.

    Edge cases and common mistakes

    • Empty input. With an empty vector the range is empty, the loop never runs, and the function returns an empty vector.
    • Exactly one pair. ["Ann", "Lee"] gives ["Ann Lee"].
    • An odd number of names. The task promises pairs, so this shouldn't happen. If it did, the last index would be even, and names[index + 1] would read one position past the end. Indexing out of bounds panics, so ["A", "B", "C"] would stop the program with an "index out of bounds" message.
    • Forgetting mut. Without let mut, the compiler rejects answer.push(name), because pushing changes the vector.
    • Stepping by 1. A plain for index in 0..names.len() would also pair each last name with the next first name, producing strings like "Doe Andy", and the final index would read past the end and panic.
    • Missing space. "{}{}" would glue the names together as "JohnDoe".
    • Returning inside the loop. Only the first full name would come back.

    Testing

    • ["John", "Doe", "Andy", "Smith", "Mary", "Johnson"] gives ["John Doe", "Andy Smith", "Mary Johnson"].
    • ["Ann", "Lee"] gives ["Ann Lee"].
    • [] gives [].
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free