Removing a value
s -= x takes x out of a mutable set s. If x is not in the set, nothing happens: there is no error and no change.
val colors = scala.collection.mutable.Set("red", "blue", "green")
colors -= "blue"
colors -= "pink"
After these lines colors holds "red" and "green". Removing "pink", which was never there, is harmless. That makes -= convenient when you want a value gone and don't care whether it was present.
If you do need to know, the method remove does the same job and returns true when the value was in the set and false when it was not.
Sets differ from buffers here. Using -= on an ArrayBuffer removes only the first matching value, so ArrayBuffer("a", "b", "a") -= "a" leaves ArrayBuffer(b, a). A set holds each value once, so removing it once is always enough.
Looping over a set
for (x <- s) runs its body once for each value in the set. A set has no fixed order, so the values can come in an order different from the one you added them in.
for (color <- colors) {
println(color)
}
This prints red and green, in either order. Loop over a set when the order cannot change your answer: a total, a count or a yes-or-no check all come out the same.
The exercise
The set found holds the words a player found in a word game. The words "qqq" and "zzz" are not allowed, so both are removed. The player never found "zzz", and removing it changes nothing. Then each remaining word scores one point per letter, so the loop adds each word's length to score.
- Remove
"qqq"and"zzz"with-=, one per line. - Below
var score = 0, writefor (word <- found)and its closing brace. - Inside the loop, add
word.lengthtoscore.
class Solution {
def mainFunction(): Unit = {
val words = scala.collection.mutable.ArrayBuffer("cat", "tree", "sun", "qqq", "moon")
val found = scala.collection.mutable.Set[String](words.toSeq: _*)
found -= "qqq"
found -= "zzz"
println(s"${found.size} words")
var score = 0
for (word <- found) {
score += word.length
}
println(s"$score points")
}
}
The output is:
4 words
14 points
Four words are left: cat, tree, sun and moon. Their lengths are 3, 4, 3 and 4, which add up to 14, in whatever order the loop visits them.
Why the order cannot matter here
The loop adds lengths to one running total. Addition gives the same sum in any order, so the answer is 14 whichever word the loop reaches first. A task such as "print the words as they come" could not be tested reliably, because the set decides the order.
Common mistakes
- Declaring
scorewithval. It changes inside the loop, so it needsvar. - Putting
printlnfor the score inside the loop. It would print once per word instead of once at the end. - Removing from a set while looping over that same set. Changing a collection during its own loop can skip values or give surprising results, so decide what to remove first and remove it after the loop.
- Depending on the order of the loop, for example "the first word", which a set does not define.
Key takeaways
-=removes a value and does nothing if it isn't there.for (x <- s)visits each value once, in no fixed order.- Totals, counts and checks are safe answers for a loop over a set.
