Problem overview
addIfMissing receives a shopping list items, an array of strings, and a word item. It adds item at the end only when the list does not already hold it, and returns the list. When the word is already there, the list stays as it is. The list may start empty.
With ["milk", "eggs"] and "bread" the result is ["milk", "eggs", "bread"]. With "milk" instead, the result is ["milk", "eggs"]. With an empty list and "apples" the result is ["apples"].
Approach
Ask the array first, then act. items.includes(item) is true when the word is there, and ! turns that around. Only inside that condition does push add the word at the end. This way the list never gets the same word twice.
Step by step
- Write the check. An
ifwith the condition!items.includes(item). Close its brace right away so the next step goes inside it. - Add the word. Inside the
if,items.push(item)appends it. - Return the list. The
returngoes after theif, so it runs in both cases: with the new word added, or with the list unchanged.
The solution in TypeScript
class Solution {
addIfMissing(items: string[], item: string): string[] {
if (!items.includes(item)) {
items.push(item);
}
return items;
}
}
On the three examples it returns:
[ 'milk', 'eggs', 'bread' ] [ 'milk', 'eggs' ] [ 'apples' ]
Why the order of the lines matters
The check has to come before the push. Once the word is pushed, includes would always be true, so a check afterwards tells nothing. Asking first and then acting is a pattern you will meet whenever a collection must not hold duplicates.
The parameter is named item and the array items: they differ by one letter, so read them carefully. items.includes(item) asks whether the whole list contains the single word.
Why not just compare in a loop?
You could walk the array yourself and set a flag when a word matches, then push if the flag is still false. That needs a loop, a variable and a second condition, and all of it only repeats what includes already does. When a method names the question you are asking, prefer it: the code reads like the sentence "if the list does not include the item, add it".
Edge cases and common mistakes
- Empty list.
[].includes("apples")isfalse, so the word is added and becomes the only item. - Pushing without the check.
["milk", "eggs"]would become[ 'milk', 'eggs', 'milk' ]for the word"milk". - Returning inside the
if. When the word is already there, the function would then return nothing. Put thereturnafter the block. - Exact text.
includesis case-sensitive, but the lesson's words are all lowercase.
Another way and testing
indexOf returns -1 when the word is missing, so if (items.indexOf(item) === -1) works the same way: it gives [ 'milk', 'eggs', 'bread' ] for "bread" and [ 'milk', 'eggs' ] for "milk". includes reads closer to the question being asked, so it is the better choice here.
Calling the function twice with the same word shows the guard working. Starting from ["milk"], two calls with "bread" leave [ 'milk', 'bread' ], not two breads. Like push, the function changes the array it receives and returns that same array.
