Problem overview
shout receives a list of lowercase words and returns a new list where each word is "shouted": written in capital letters with ! added at the end. "hey" becomes "HEY!". The order stays the same and every word is kept, repeated ones included.
For ["hey", "you"] the result is [HEY!, YOU!]. For ["go"] it is [GO!], and for ["no", "no", "no"] it is [NO!, NO!, NO!]. (Kotlin prints a list with brackets and commas.)
Approach
Each word turns into exactly one new word, in the same place. That is what map is for: it applies a lambda to every item and collects the results in a new list of the same length. Inside the lambda, it is the current word.
The change for one word has two parts. uppercase() returns the word in capital letters, and + "!" adds the exclamation mark at the end. Strings can't be changed in place, so both create new strings, and the original list is not touched.
Step by step
- Build
shoutedwithwords.map { it.uppercase() + "!" }. - Return
shouted.
The solution in Kotlin
class Solution {
fun shout(words: List<String>): List<String> {
val shouted = words.map { it.uppercase() + "!" }
return shouted
}
}
On the examples it returns:
[HEY!, YOU!]
[GO!]
[NO!, NO!, NO!]
A string template does the same job: words.map { "${it.uppercase()}!" } gives [HEY!, YOU!] for the first example.
The same with a loop
For comparison, here is the loop that map replaces:
val shouted = mutableListOf<String>()
for (word in words) {
shouted.add(word.uppercase() + "!")
}
return shouted
It returns [HEY!, YOU!] for the first example, the same as the one-line version. The loop makes the empty list, adds one result per word and returns it. map does all three for you.
What map can return
The lambda decides the type of the new list's items. Here it returns a String for each String, so the result is again a List<String>, which matches the function's return type. A lambda that returned a number would make a list of numbers: words.map { it.length } on the same two words gives [3, 3]. So when the compiler complains about the return type, check what the lambda produces.
The new list is as long as words. This is the quickest check that you picked the right tool: if each item turns into exactly one item, use map.
Testing
Try a list that has a repeated word and a single word. The three examples above cover both. A list that is already shouted, such as ["HEY"], would come out as [HEY!], but the constraints promise only lowercase letters a to z, so the lesson's tests never send it.
Edge cases and common mistakes
- Calling
it.uppercasewithout parentheses.uppercase()is a function, so it needs(). Without them the compiler reportsfunction invocation 'uppercase()' expected. - Using
toUpperCase(). This older name is a compile error in current Kotlin: the compiler says it is deprecated and to useuppercase()instead. - Using
filterby mistake.filterwould keep or drop words but not change them. - Expecting
wordsto change. It doesn't.mapbuilds a new list, so return the result. - Repeated words are not merged:
mapproduces one answer per item, so three copies in give three copies out.
