Start learning free

LESSON 239 OF 678 · SETS

Removing From Sets in Swift: remove and for-in

Lesson Read the full explanation

TL ; DR:

remove(x) takes x out of a set. A for loop visits every value once, in no fixed order.


var colors = Set(["red", "blue", "green"])
colors.remove("blue")
colors.remove("pink")           // not in it, nothing happens

for color in colors {
    print(color)                // red and green, in any order
}


Full lesson:

s.remove(x) removes x from the set s. It returns the removed value. If x wasn't there, nothing happens and it returns nil.

for x in s visits each value of the set once. The order isn't fixed. Swift may even change it from one run to the next.

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

    SWIFT · SETS

    Removing From Sets in Swift, explained

    Removing a value

    s.remove(x) takes x out of the set s. If x was there, remove returns it. If it wasn't, nothing happens, there is no error, and remove returns nil. The return type is an optional for that reason.

    var colors = Set(["red", "blue", "green"])
    print(colors.remove("blue") as Any)
    print(colors.remove("pink") as Any)
    print(colors.sorted())
    

    This prints:

    Optional("blue")
    nil
    ["green", "red"]
    

    You can ignore the returned value, and the compiler doesn't warn about it. The set must be declared with var, since removing changes it. The sorted() call in the last line is there only to print in a stable order.

    Looping over a set

    for x in s visits each value of the set once. The order isn't fixed, and Swift may even change it from one run to the next. So loop over a set when the order doesn't matter: a total, a count or a yes-or-no check all give the same answer in any order.

    for color in colors {
        print(color)
    }
    

    That prints red and green, one per line, in either order.

    Taking out several values at once

    When the values to remove follow a rule, filter is another way to get there. On a set it returns a new set holding only the values that pass the test. For example, keep.filter { $0 == "b" } on a set of "a", "b", "c" and "d" gives a set with just "b". The original set is not changed.

    You can also call remove inside a loop over the same set. The loop keeps walking through the values the set held when it began, and the removals change the set itself. For a set of "a", "b", "c" and "d", removing "a" and "c" inside the loop leaves ["b", "d"]. Still, a loop that changes what it loops over is easy to misread, so removing by name, as in the exercise, is usually clearer.

    An empty set

    Removing the last value leaves an empty set, not an error. Its isEmpty is true and its count is 0, and a loop over it simply runs zero times. That makes a total over a set safe when nothing is left: the score stays at its starting value of 0.

    The lesson's exercise

    A word game keeps the words a player found in a set:

    let words = ["cat", "tree", "sun", "qqq", "moon"]
    var found = Set(words)
    

    The words "qqq" and "zzz" aren't allowed, so remove both. The player never found "zzz", and removing it simply does nothing. After the two removals, the set holds 4 words:

    found.remove("qqq")
    found.remove("zzz")
    print("\(found.count) words")
    

    A word scores one point per letter, so the second part adds up the lengths. Start score at 0, loop over found with the loop variable word, and add word.count each time:

    var score = 0
    for word in found {
        score += word.count
    }
    print("\(score) points")
    

    The words left are cat, tree, sun and moon, so the score is 3 + 4 + 3 + 4 = 14. The program prints:

    4 words
    14 points
    

    The total doesn't depend on the order the loop visits the words, which is what makes a set loop safe here.

    Common mistakes

    • Expecting an error for a missing value. Removing something that isn't there is allowed. The optional result is nil.
    • Removing from a let set. This is a compile error. Use var.
    • Using the order. A loop that keeps "the first word" or prints the words and expects a fixed sequence will behave differently between runs.
    • Using word.length. A Swift string has count, which counts characters.

    Key takeaways

    • s.remove(x) removes x and returns it, or returns nil if it wasn't there.
    • for x in s visits every value once, in no fixed order.
    • Totals, counts and checks are safe answers from a set loop.
    Keep going with Swift500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free