Start learning free

LESSON 238 OF 677 · SETS

Removing From a Set and Looping Over It in Scala

Lesson Read the full explanation

TL ; DR:

-= x takes x out of a mutable set. A for loop visits every value once, in no fixed order.


val colors = scala.collection.mutable.Set("red", "blue", "green")
colors -= "blue"
colors -= "pink"                // not in it, nothing happens

for (color <- colors) {
    println(color)              // red and green, in any order
}


Full lesson:

s -= x removes x from the mutable set s. If x isn't in it, nothing happens.

for (x <- s) visits each value of the set once. The order isn't fixed. It may differ from the order you added the values in.

So loop over a set when the order doesn't matter. A total, a count and a check are fine.


Your task

In a word game, the set found holds the words a player found. The words "qqq" and "zzz" aren't allowed. Remove both from found.

The player never found "zzz", so removing it changes nothing.

Then add up the points. A word scores one point per letter. Loop over found and add each word's length to score.

The code already prints how many words are left, and the points.

Expected output:

4 words
14 points
STEP 1 OF 3
    Ctrl + Enter to check

    SCALA · SETS

    Removing From Sets in Scala, explained

    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.

    1. Remove "qqq" and "zzz" with -=, one per line.
    2. Below var score = 0, write for (word <- found) and its closing brace.
    3. Inside the loop, add word.length to score.
    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 score with val. It changes inside the loop, so it needs var.
    • Putting println for 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.
    Keep going with Scala500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free