Start learning free

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

Shout the Words in Rust: map and collect on a Vec

Practice Read the full explanation

You get a Vec called words. Each word in it is in lowercase letters.

Return a new Vec with every word shouted.

To shout a word, write it in capital letters and put ! after it. So "hey" becomes "HEY!".

Keep the words in the same order.

 

Example 1:

Input: words = ["hey", "you"]
Output: ["HEY!", "YOU!"]
Explanation: Both words are in capital letters now.
Each one has a ! at the end.

Example 2:

Input: words = ["go"]
Output: ["GO!"]
Explanation: One word goes in, one word comes out.

Example 3:

Input: words = ["no", "no", "no"]
Output: ["NO!", "NO!", "NO!"]
Explanation: A word that repeats is shouted each time.

 

Constraints:

  • words has at least one word.
  • Every word has only the letters a to z.
STEP 1 OF 2
    Ctrl + Enter to check

    RUST · TUPLES, SORTING & BUILT-INS

    Shout The Words in Rust, explained

    Problem overview

    The function shout receives a vector of lowercase words, words, and returns a new vector in which every word is shouted: written in capital letters with ! after it. The order stays the same and a repeated word is shouted each time.

    For ["hey", "you"] the answer is ["HEY!", "YOU!"]. For ["go"] it is ["GO!"], and for ["no", "no", "no"] it is ["NO!", "NO!", "NO!"].

    Approach

    The job is the same for every word: turn one word into a new one. Iterators have a method for that, map, which applies a closure to each item and produces the results in the same order. Then collect() gathers those results into a vector.

    Calling iter() on the vector borrows it, so the closure sees each word as a reference and the original vector is left untouched. For each word, to_uppercase() builds a new String in capital letters, and adding "!" with + appends the mark to that new string.

    Step by step

    1. Name the result type. Write let shouted: Vec<String> = .... The type after the name tells collect() what to build; without it the compiler reports "type annotations needed", because collect() can produce many kinds of collection.
    2. Start the chain with words.iter().
    3. Map each word with |word| word.to_uppercase() + "!". The left side of + is an owned String, which is what Rust requires: adding to a borrowed reference does not compile.
    4. End with collect() to build the vector.
    5. Return shouted. The input vector did not change; the answer is a new one.

    The solution in Rust

    impl Solution {
        fn shout(words: Vec<String>) -> Vec<String> {
            let shouted: Vec<String> = words.iter().map(|word| word.to_uppercase() + "!").collect();
            return shouted;
        }
    }

    Iterators in Rust are lazy: map alone does nothing until something consumes the iterator, and collect() is what runs the whole chain. A closure with one parameter is written between vertical bars, and its last expression is its result, so no return is needed inside it.

    About to_uppercase

    The method to_uppercase() never changes the original text, because strings are not edited in place this way. It returns a new String. For the lowercase letters a to z used in this lesson, the result is simply the capital version of each letter. The method also handles other alphabets, and a single letter may turn into more than one in some of them, which is why it returns a String and not a single character.

    Another way

    format!("{}!", word.to_uppercase()) builds the same string without using +. Both forms give ["HEY!", "YOU!"] for the first example.

    Testing

    The first and third examples give:

    ["HEY!", "YOU!"]
    ["NO!", "NO!", "NO!"]

    The words are borrowed by iter(), so after the call the input vector still holds ["hey", "you"]. If the caller no longer needs the input vector, into_iter() would hand over the words themselves instead of borrowing them; the result for this problem is the same.

    Edge cases and common mistakes

    • Forgetting the type on shouted. The compiler cannot guess the collection and stops with an error.
    • Writing word + "!" with the loop's reference. The compiler says it cannot add a &str to a &String, and notes that concatenation needs an owned String on the left. to_uppercase() provides one.
    • Forgetting collect(). The result would be an iterator, not a vector.
    Keep going with Rust500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free