Removing a value
s.delete(x) takes x out of the set s. It returns true if the value was there and false if it was not. Deleting a value that is missing is not an error: nothing happens.
let words: string[] = ["cat", "tree", "sun", "qqq", "moon"];
let found: Set<string> = new Set(words);
console.log(found.delete("qqq"));
console.log(found.delete("zzz"));
console.log(found.size + " words");
This prints:
true
false
4 words
The first call found "qqq" and removed it. The second found nothing and left the set alone. Because a missing value is harmless, you never need an if (s.has(x)) check before calling delete.
Looping over a set
for (let x of s) visits each value of the set once. A set has no indexes, so a counting loop with s[i] does not work. Use for...of.
A TypeScript set loops in the order the values were added. Many other languages promise no order at all, so a set is best for work where the order does not matter, such as a total, a count or a check. Those give the same answer in any order.
Deleting while looping
Deleting the value you are currently visiting is allowed. For new Set([1, 2, 3, 4]), a loop that deletes every even value leaves 1 3. It is still simpler to read when the loop only reads the set, and the changes happen in separate statements.
Counting while looping
The loop body can do more than add. This one counts the words with more than three letters. The pattern is the same as for a total: start a variable at 0 before the loop, change it inside, and read it after.
let found: Set<string> = new Set(["cat", "tree", "sun", "moon"]);
let longWords: number = 0;
for (let word of found) {
if (word.length > 3) {
longWords += 1;
}
}
console.log(longWords);
It prints 2, for "tree" and "moon".
Mistakes to avoid
- Using
for...inon a set.for...ingives the keys of an object. A set has no such keys, so the loop body never runs and the program carries on silently.for...ofis the loop for the values of a set. - Indexing. Reading
found[0]or looping withi < found.sizeandfound[i]givesundefinedevery time, because a set has no positions. - Checking before deleting. An
ifarounddeleteis extra code. The call already does nothing for a missing value. - Removing everything.
found.clear()empties the whole set at once; after it,found.sizeis 0.
The exercise
In a word game, the set found holds the words a player found. The words "qqq" and "zzz" are not allowed, so both have to go. The player never found "zzz", so removing it changes nothing. Then each word scores one point per letter, and score has to hold the total.
- Call
found.delete("qqq")andfound.delete("zzz"), one per line. - Write a
for...ofloop overfoundwithlet word. - Inside it, add
word.lengthtoscore.
let words: string[] = ["cat", "tree", "sun", "qqq", "moon"];
let found: Set<string> = new Set(words);
found.delete("qqq");
found.delete("zzz");
console.log(found.size + " words");
let score: number = 0;
for (let word of found) {
score += word.length;
}
console.log(score + " points");
The output is:
4 words
14 points
The four words left are cat, tree, sun and moon, and 3 + 4 + 3 + 4 = 14.
Key takeaways
delete(x)removes a value and returns whether it was there; a missing value is not an error.for...ofvisits every value of a set once, in the order they were added.- Sets have no indexes, so index-based loops do not work on them.
