Problem overview
The function addIfMissing gets a shopping list items (a MutableList<String>) and a word item. It adds item at the end only when the list doesn't hold it yet, and returns the list. When the word is already there, the list stays as it is. The list may be empty.
With ["milk", "eggs"] and "bread", the answer is ["milk", "eggs", "bread"]. With "milk" the list stays ["milk", "eggs"]. With an empty list and "apples", the answer is ["apples"].
Approach
Ask the list whether it holds the word, and add only when the answer is no. Kotlin's !in does exactly that: item !in items is true when no entry equals item, and it is true for an empty list. The check compares by content, so a different string object with the same letters counts as present.
Step by step
- Test for absence. An
ifwith the conditionitem !in items, and its closing brace written right away. - Add inside it.
items.add(item)puts the word at the end. It only runs for a new word. - Return
itemsafter theif, so both outcomes return the list.
The solution in Kotlin
class Solution {
fun addIfMissing(items: MutableList<String>, item: String): MutableList<String> {
if (item !in items) {
items.add(item)
}
return items
}
}
On the three examples it gives (values separated by spaces):
milk eggs bread
milk eggs
apples
The function changes the list it receives and returns that same list. Putting the return inside the if would leave the function without a result when the word is already present, and Kotlin would reject the code, so keep it after the closing brace.
Another way
The !in operator is short for a call to contains, so the condition can also be written !items.contains(item):
if (!items.contains(item)) {
items.add(item)
}
It behaves the same way: for ["milk", "eggs"] and "milk" the list stays [milk, eggs]. The !in form reads closer to plain English, so the lesson uses it.
How the check works
The list compares the word with its entries one by one, from the first, and stops at the first match. For a list of up to nine words that is instant. It also means the function doesn't remove duplicates that were already in the list: it only avoids creating a new one. If the list already held two "milk" entries, they would both stay.
Edge cases and common mistakes
- Empty list. Nothing is in it, so the word is added. No special case is needed.
- Adding without the check.
items.add(item)alone would put a second"milk"in the list. - Reversing the condition. With
item in itemsthe word is added only when it is already there. - Case. The words are lowercase, so
"Milk"doesn't come up here, but in general"Milk"and"milk"are different words.
Calling it several times
Because the function keeps what it adds, calling it again with the same word changes nothing. Starting from an empty list and offering "tea", "tea" and "jam" in turn leaves [tea, jam]: the second "tea" finds the first one and is skipped.
Testing
["milk", "eggs"]and"bread"givesmilk eggs bread.["milk", "eggs"]and"milk"givesmilk eggs.[]and"apples"givesapples.
