## Introduction

The **Python set **is an iterable data structure that represents an **unordered collection** of **unique elements**. Python sets are a concrete implementation of the mathematical concept of a set. Sets are useful in cases where you need to determine whether an item is associated with a group of other items or not.

For example, a set can be used to associate students with a class (class in the educational sense, not the object-oriented programming sense). Each class is a set of students that determines whether any specific student is in it or not. For this purpose, each student can appear in a class only once, and we don’t care about the order of students in a class. The set data structure is, therefore, a good fit for this application.

## Set Literals

A set literal is defined using curly braces `{}`

that surround comma-separated values.

**Example:**

my_set = {1, 2, 3, 4, 5}

In this example, `my_set`

contains five distinct integers.

Set literals share the curly brace syntax with Python dictionaries, but can be distinguished from those because they don’t contain key-value pairs with colons.

**Example:**

my_set = { "one", "two", "three"} # This is a set. my_dictionary = { "one": 1, "two": 2, "three": 3} # And this is a dictionary.

Note that sets do not allow duplicate elements, and if you try to create a set with duplicate values, the duplicates will be removed.

**Example:**

my_set = {1, 2, 2, 3, 3, 3} print(my_set)

**Output:**

{1, 2, 3}

## The Python Set Constructor

Sets can also be created with the `set()`

constructor function by passing any iterable object. This constructor will convert the iterable into a set and eliminate any duplicate items, just as the curly brace `{}`

syntax does.

**Example:**

my_list = [1, 2, 2, 3, 3] my_set = set(my_list) print(my_set)

**Output:**

{1, 2, 3}

### Creating an Empty Set

To create an empty set, you cannot use `{}`

alone because it creates an empty dictionary. Instead, use the `set()`

constructor with no argument.

**Example:**

empty_set = set() print(empty_set)

**Output:**

set()

The empty set prints out as “`set()"`

and not “`{}`

” since the meaning of “`{}`

” is reserved for empty dictionaries.

## Hashability and Immutability of Set Elements

Each element in a set must be hashable. Hashable objects have a fixed and unique identifier, which condenses its content into a single number, known as a hash value. This hash value is used to quickly locate and retrieve items within the set, making set operations like insertion, deletion, and membership checks extremely efficient.

In Python, the hashability of an object depends on its immutability. Immutable objects, such as integers, strings, and tuples, cannot change after creation. Python can then compute a consistent hash value for these objects.

However, mutable objects such as lists, dictionaries, and sets are not hashable because their content can change. Python raises an error if you try to add a mutable object to a set.

The following example attempts to create a set of lists, which are not hashable, resulting in an error.

**Example:**

my_set = {[1,2], [3,4]}

**Output:**

... TypeError: unhashable type: 'list'

## Adding Elements to a Set

You can add elements to a set using the `add()`

method. The `add()`

method allows you to insert a single element into the set.

**Example:**

my_set = {1, 2, 3} my_set.add(4) print(my_set)

**Output:**

{1, 2, 3, 4}

Note that since sets are composed of unique values, adding an element that’s already in the set will have no effect.

## Removing Elements from a Set

### Using *remove()*

The `remove()`

method removes a specified element from the set.

**Example:**

my_set = {1, 2, 3, 4} my_set.remove(3) print(my_set)

**Output:**

{1, 2, 4}

If the item is not found in the set, `remove()`

raises a `KeyError`

exception.

**Example:**

my_set = {1, 2, 3, 4} my_set.remove(5)

**Output:**

... KeyError: 5

### Using *discard()*

The `discard()`

method also removes a specified item from the set. However, if the item is not found, it does nothing and does not raise an error.

The following example demonstrates using `discard()`

on an item that’s in the set. In this case, it works like `remove()`

.

**Example:**

my_set = {1, 2, 3, 4} my_set.discard(3) print(my_set)

**Output:**

{1, 2, 4}

The next example demonstrates using `discard()`

with an item that is not in the set. This time, there is no error, and the set remains unchanged.

**Example:**

my_set = {1, 2, 3, 4} my_set.discard(5) print(my_set)

{1, 2, 3, 4}

### Using *pop()*

The `pop()`

method removes and returns one arbitrary element from the set. Since sets are unordered, there’s no guarantee which element will be removed.

**Example:**

my_set = {1, 2, 3, 4} popped_element = my_set.pop() print(popped_element) print(my_set)

**Output:**

1 {2, 3, 4}

### Using *clear()*

The `clear()`

method removes all elements from a set, leaving it empty.

**Example:**

my_set = {1, 2, 3, 4} my_set.clear() print(my_set)

**Output:**

set()

## Length of a Set

To find the number of elements in a set, you can use the built-in `len()`

function.

**Example:**

my_set = {1, 2, 3, 4, 5} set_length = len(my_set) print(set_length)

**Output:**

5

## Frozen Sets

A frozen set is an immutable version of a set and has a type of `frozenset`

. Once created, you cannot modify its content by adding, removing, or changing elements.

A frozen set is useful when you need a set-like object that can be used as a dictionary key or included in another set.

You can create a frozen set with the `frozenset()`

constructor function, which accepts any iterable as an argument and creates a frozen set from it. It works like the `set()`

constructor, except that it generates a frozen set.

The following example creates a frozen set from a set literal.

**Example:**

my_set = frozenset({1, 2, 3}) print(my_set)

**Output:**

frozenset({1, 2, 3})

The next example demonstrates how `frozenset()`

can create a frozen set from an iterable, a list in this case, while eliminating duplicates.

**Example:**

my_set = frozenset([1, 2, 2, 3, 3, 3]) print(my_set)

**Output:**

frozenset({1, 2, 3})

## Set Operations

Python sets support the common set operations associated with mathematical set theory such as union, intersection, and difference. They additionally support testing whether one set is a subset or a superset of another, or if two sets are disjoint. These operations will be introduced in separate lessons.

## Summary & Reference for Python Set Basics

A Python set is a data structure that represents an unordered collection of unique elements.

To create a set literal, use curly braces `{}`

that surround comma-separated items. Duplicate elements are automatically removed, making sets ideal for managing unique collections of data.

my_set = {1, 2, 2, 3, 3, 3} # my_set --> {1, 2, 3}

Use the Python set constructor function, `set()`

, to create sets from iterable objects, ensuring unique elements in the resulting set.

my_list = [1, 2, 2, 3, 3] my_set = set(my_list) # my_set --> {1, 2, 3}

To create an empty set, use `set()`

constructor and no arguments. Using `{}`

alone, creates an empty dictionary and not a set.

empty_set = set() print(empty_set) # This prints out 'set()' and not '{}' because empty curly braces mean a dictionary.

Elements in a set must be hashable and immutable. Attempting to add to or create sets with objects that are not hashable/immutable, such as lists, will result in an error.

my_set = {[1,2], [3,4]} # --> TypeError: unhashable type: 'list'

An element can be added to a set using the `add()`

method.

my_set = {1, 2, 3} my_set.add(4) # my_set --> {1, 2, 3, 4}

An element can be removed from a set with the `remove()`

method. If the element is not in the set, a `KeyError`

exception is raised.

my_set = {1, 2, 3, 4} my_set.remove(3) # my_set --> {1, 2, 4}

The `discard()`

method also removes a specified element from the set, but it does not generate an error if it’s not there.

my_set = {1, 2, 3, 4} my_set.discard(3) # my_set --> {1, 2, 4}

The `pop()`

method removes and returns one arbitrary element from the set.

my_set = {1, 2, 3, 4} popped_element = my_set.pop() # popped_element --> 1 my_set --> {2, 3, 4}

The `clear()`

method removes all elements from a set.

my_set = {1, 2, 3, 4} my_set.clear() # my_set --> set()

To determine the length of a set, use the built-in `len()`

function.

my_set = {1, 2, 3, 4, 5} set_length = len(my_set) # set_length --> 5

You can create a frozen set with the `frozenset()`

constructor. Those are sets that are hashable and immutable, and as such can be used as dictionary keys and be members of other sets. Like the regular set constructor, `frozenset()`

creates a set out of any iterable, eliminating duplicates.

my_set = frozenset({1, 2, 3}) # my_set --> frozenset({1, 2, 3})