runtime
63 / 250
lesson 63 Comprehensions · intermediate

Distinct values with a set comprehension

A set comprehension collects the distinct values a collection contains. Repeats disappear, and so does the order.

You'll be able to
  • Build a set of distinct values with {expression for item in items}
  • Compare two sets with difference and union to answer who-is-missing questions
  • Sort a set when you need to show it, because a set has no order and no positions
The idea

*Which countries do our users come from?* is not *list every user's country*: you want each country once. In the Collection Algorithms module you skipped values already seen. A set does that by itself: it holds each value at most once.

A set comprehension uses braces without a colon: {expression for item in items}. A set has no order, so when you print it for people, sort it first with sorted, which gives a list.

Run each example to see what it prints. Running examples doesn't count toward progress.

example-1.py · Countries our users come from
users = [
    {"user_id": 6078, "country": "Canada"},
    {"user_id": 7345, "country": "Brazil"},
    {"user_id": 7712, "country": "Canada"},
    {"user_id": 8020, "country": "India"},
]
countries = {user["country"] for user in users}
print(len(countries))
print(sorted(countries))

Because a set has no order, it has no positions either. Asking for the first item is an error, not the first country you added.

example-2.py · A set has no position 0
countries = {"Canada", "Brazil", "India"}
print(countries[0])

Sets earn their keep when you compare two collections. Build a set from each, then let difference (see Dictionaries & Sets) answer *who is in the first but not the second*. Checking in against a set is also fast however large it gets, which matters when you check thousands of IDs.

example-3.py · Users who never rated a film
def never_rated(users, ratings):
    everyone = {user["user_id"] for user in users}
    raters = {rating["user_id"] for rating in ratings}
    return everyone.difference(raters)

users = [{"user_id": 6078}, {"user_id": 7345}, {"user_id": 7712}, {"user_id": 8020}]
ratings = [
    {"user_id": 6078, "movie_id": 2439},
    {"user_id": 6078, "movie_id": 935},
    {"user_id": 8020, "movie_id": 266},
]
print(sorted(never_rated(users, ratings)))

When to use it: distinct values (countries, tags, airports), and *in A but not B* questions. Mistakes to avoid: expecting the set to keep the order you added things in; indexing a set; and writing {} for an empty set. Empty braces make an empty dictionary; an empty set is written set().

Review
  • {expression for item in items} keeps each value once. Normalise first if different spellings should count as one.
  • A set has no order and no positions: sort it to show it, and use difference or union to compare.
  • {} is an empty dictionary; an empty set is set().
  • Next: two for clauses in one comprehension, to flatten lists inside lists.
Practise this

Loading your progress…

To master this lesson, solve both challenges without hints or the answer, and pass the concept check.

Distinct values with a set comprehension — Comprehensions · Runtime