Start learning free

LESSON 234 OF 673 · SETS

Removing From Sets in Python: discard and Looping

Lesson Read the full explanation

TL ; DR:

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


colors = set(["red", "blue", "green"])
colors.discard("blue")
colors.discard("pink")     # not in it, nothing happens

for color in colors:
    print(color)           # red and green, in any order


Full lesson:

s.discard(x) removes x from the set s. If x isn't in it, nothing happens.

Python also has s.remove(x). It works the same when x is there. When it isn't, remove stops the program with a KeyError. Use discard when you aren't sure.

for x in s visits each value of the set once. The order isn't fixed. It may differ from the order you added the values in, and 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.

Don't remove values from a set while you loop over it. Python stops with a RuntimeError. Remove first, then loop.


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

    PYTHON · SETS

    Removing From Sets in Python, explained

    discard and remove

    s.discard(x) takes x out of the set s. If x is not in the set, nothing happens. Python also has s.remove(x), which works the same when x is there. When it is not, remove stops the program with a KeyError.

    found = set(["cat", "tree", "sun"])
    found.discard("sun")
    found.discard("zzz")
    print(len(found))
    
    found.remove("zzz")
    2
    Traceback (most recent call last):
      ...
    KeyError: 'zzz'

    Use discard whenever you are not sure the value is in the set. Use remove only when a missing value would be a bug that you want to hear about.

    Looping over a set

    for x in s visits each value of the set once. The order is not fixed: it can differ from the order you added the values in, and from one run to the next. So a set loop suits jobs where order does not matter, such as a total, a count or a check.

    Do not remove values from a set while looping over it. Python stops with RuntimeError: Set changed size during iteration. Remove first, then loop, or build a second collection of the values to keep.

    The exercise, step by step

    A word game keeps the words a player found in the set found. The words "qqq" and "zzz" are not allowed. The task is to remove both, then score one point per letter over the words that are left. The starter code prints how many words remain and the score.

    1. Call found.discard("qqq") and found.discard("zzz"). The player never found "zzz", so the second call changes nothing and raises no error. With remove that line would crash.
    2. Below score = 0, write for word in found:.
    3. Inside the loop, add len(word) to score.
    words = ["cat", "tree", "sun", "qqq", "moon"]
    found = set(words)
    
    found.discard("qqq")
    found.discard("zzz")
    print(len(found), "words")
    
    score = 0
    for word in found:
        score += len(word)
    print(score, "points")
    4 words
    14 points

    The four words left are cat, tree, sun and moon, and 3 + 4 + 3 + 4 = 14. Whatever order the loop visits them in, the total is the same.

    Choosing between them

    The two methods differ only for a missing value. A game that takes banned words out of whatever the player found should not crash when the banned word was never found, so discard fits. If your program is sure that a value is in the set, remove turns a wrong assumption into an immediate error with the missing value in the message, instead of letting the mistake pass unnoticed. In this exercise the second banned word is absent by design, which is why the lesson uses discard for both calls, so the two lines look alike.

    Common mistakes

    • Using remove("zzz") for a word that may be absent.
    • Expecting the loop to print words in the order of the list. A set does not keep it.
    • Calling discard inside the scoring loop on the set being looped over.

    Key takeaways

    • discard(x) is safe when x may be missing; remove(x) raises KeyError.
    • A set loop visits every value once, in no fixed order.
    • Do not change the size of a set during its own loop.
    Keep going with Python500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free