Problem overview
shout(words) receives an array of lowercase words and returns a new array in which every word is shouted: written in capital letters, with ! at the end. The order stays the same. For ["hey", "you"] the answer is ["HEY!", "YOU!"]. A repeated word is shouted every time, so ["no", "no", "no"] becomes ["NO!", "NO!", "NO!"].
Approach
Every word turns into exactly one new word, in the same place. That is the job of the array method map. It calls a function on each item and collects the results in a new array of the same length. You could write a loop with push; map says the same thing in one line.
The function for one word has two parts. word.toUpperCase() gives the word in capital letters, and + "!" adds the exclamation mark after it.
Step by step
- Build
shoutedby callingwords.mapwith an arrow function that takes awordand gives backword.toUpperCase() + "!". - Return
shouted.
The solution in JavaScript
class Solution {
shout(words) {
let shouted = words.map(word => word.toUpperCase() + "!");
return shouted;
}
}
Read word => word.toUpperCase() + "!" as "take word, give back the shouted word". When an arrow function has no curly braces, the value after => is returned automatically.
The examples give:
["HEY!","YOU!"]
["GO!"]
["NO!","NO!","NO!"]
map does not change words. After shouting ["hey", "you"], the original array is still ["hey", "you"].
The same job with a loop
Before map, the job was done with a loop: create an empty array, go through words and push each shouted word. Both versions return ["HEY!","YOU!"] for ["hey", "you"]. The map version has no empty array to start, no push and no loop variable to name, so there is less to get wrong.
The function you give to map may also take a second argument, the index of the item, as in (word, i) => i + ":" + word. For ["hey", "you"] that gives ["0:hey", "1:you"]. This lesson does not need the index.
Testing
Try the three examples from the statement: a two-word array, a one-word array and an array that repeats a word. The outputs are the arrays shown above. A good extra check is the length: whatever you pass in, shout(words).length equals words.length, because every word produces exactly one result. Another is to print words after the call and confirm that it is unchanged.
Edge cases and common mistakes
- Curly braces without
return.words.map(word => { word.toUpperCase() + "!"; })gives[undefined, undefined]for two words, because a function body in braces returns nothing unless it saysreturn. - Forgetting the parentheses on
toUpperCase.word.toUpperCase + "!"does not call the method. It joins the method's own text to the!, givingfunction toUpperCase() { [native code] }!. - Order of the two changes. You can add the
!first and capitalize after:(word + "!").toUpperCase()gives the same result, because!has no capital form. - Using
forEachinstead ofmap.forEachruns a function on each item but always returnsundefined, so there is no new array to keep. Usemapwhen you want the results. - Fewer or more words.
mapalways returns the same number of items, so a single word gives a single shouted word.
