New to Programming? No Worries! Start Learning Python from Scratch — Part 4: Mastering Python Data Structures

Rohollah
Python Mastery for Beginners
20 min readAug 19, 2024

In this exciting and easy-to-follow guide, I’m going to show you one of the most important topics in Python — and really, in any programming language. That’s right, we’re talking about data structures. And don’t worry, we’ll make sure you really understand them by tackling some fun and challenging problems together. By the end of this, you’ll not only know what they are but also see why they’re so important in coding. Get ready — it’s going to be a fun and simple journey!

Data Structures In Python

In Python, there are 13 types of data structures, but since this series is for beginners, we’ll focus on just 6 of them. The 6 important data structures are:

  • Lists
  • Tuples
  • Dictionaries
  • Sets
  • Arrays

Lists

In Python, a list is a way to store a group of items in one place. You create a list by putting items inside square brackets, like this: `[1, ‘apple’, 3.14]`. Lists can hold different types of items and you can change them later. You can add new items, remove items, or sort them using built-in methods. Lists are useful for keeping and working with collections of data.

Ultimate guide to Python Lists

List Creation

In Python, you can create a list in just one line by enclosing a comma-separated sequence of elements within square brackets []. Here’s an example:

This code creates a list called favorite_fruits with four items: "Apple," "Banana," "Cherry," and "Mango." The list is then printed, showing the items in a clear and straightforward way.

# Creating a list of favorite fruits
favorite_fruits = ["Apple", "Banana", "Cherry", "Mango"]

# Printing the list
print("My favorite fruits are:", favorite_fruits)

Indexing and Slicing

List indexing in Python allows you to access individual elements of a list by using their position, with indices starting at 0 for the first element.

Here’s a compelling real-world example of how to use indexing and slicing with a list in Python:

# Imagine you have a list of days in a week
week_days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

# Indexing: Get the day at index 2 (Wednesday)
mid_week_day = week_days[2]
print("Mid-week day:", mid_week_day)

# Slicing: Get the workdays (Monday to Friday)
work_days = week_days[0:5]
print("Workdays:", work_days)

# Slicing: Get the weekend days (Saturday and Sunday)
weekend_days = week_days[-2:]
print("Weekend days:", weekend_days)

Explanation:

  • Indexing: week_days[2] returns the third element in the list, "Wednesday," since indexing starts at 0.
  • Slicing: week_days[0:5] returns a slice of the list from the first element to the fifth (excluding the fifth), which includes the workdays "Monday" through "Friday."
  • Negative Slicing: week_days[-2:] returns the last two elements of the list, "Saturday" and "Sunday," representing the weekend.

Adding Elements (Append, Extend, Insert)

When working with lists in Python, adding new elements is a common task that can be done using append, extend, and insert. Each of these methods serves a specific purpose and behaves differently:

  • Append: The append method adds a single element to the end of the list. For example, if you have a list of favorite movies and want to add a new movie, append will place it at the end of the list. This method is useful when you want to grow your list one item at a time.
  • Extend: The extend method is used when you want to add multiple elements to a list at once. Instead of adding one item like append, extend takes another iterable (like a list) and adds each of its elements to the end of the original list. This is handy when you have another list of items that you want to combine with your existing list.
  • Insert: The insert method allows you to add an element at a specific position in the list. Unlike append, which always adds to the end, insert requires two arguments: the index at which you want to insert the element and the element itself. This is particularly useful when you need to place an item in a specific spot within your list, rather than just appending it to the end.

Here’s an exciting real-world example of adding elements to a list using append, extend, and insert in Python:

# Let's say you have a list of your favorite movies
favorite_movies = ["Inception", "The Matrix", "Interstellar"]

# Append: You just watched a new movie and want to add it to the end of your list
favorite_movies.append("Tenet")
print("After appending a new movie:", favorite_movies)

# Extend: You remember a few more movies you love and want to add them all at once
more_movies = ["The Dark Knight", "Pulp Fiction"]
favorite_movies.extend(more_movies)
print("After extending with more movies:", favorite_movies)

# Insert: You realize that "The Godfather" should be at the top of your list, so you insert it at the beginning
favorite_movies.insert(0, "The Godfather")
print("After inserting a movie at the top:", favorite_movies)

Explanation:

  • Append: Adds a single movie, “Tenet,” to the end of the favorite_movies list.
  • Extend: Adds multiple movies, “The Dark Knight” and “Pulp Fiction,” to the end of the list in one go.
  • Insert: Adds “The Godfather” to the very beginning of the list, making it the first item

Removing Elements (Remove, Pop, Clear)

Removing elements from a list in Python is an essential operation, especially when you need to clean up or manage your data. There are several ways to remove elements, including remove, pop, and clear, each serving a specific purpose.

  • The remove method is used to delete the first occurrence of a specific element by value.
  • If you know the index of the element you want to remove, you can use the pop method, which not only removes the element at that index but also returns it.
  • If you need to empty the entire list, the clear method will remove all elements, leaving you with an empty list.

Real-World Example:

Imagine you have a list of tasks for the day:

tasks = ["Email clients", "Meeting with team", "Lunch with a friend", "Write report"]

# You completed "Email clients" and want to remove it from the list
tasks.remove("Email clients")
print("Tasks after removing 'Email clients':", tasks)

# The meeting with the team was canceled, so you remove it using pop (assuming it's the next task)
canceled_task = tasks.pop(0)
print(f"'{canceled_task}' was canceled, remaining tasks:", tasks)

# Finally, you decide to clear all tasks at the end of the day
tasks.clear()
print("Tasks after clearing all:", tasks)
  • Remove: The task “Email clients” is removed by value.
  • Pop: The first task (“Meeting with team”) is removed by index, and the method returns the removed task.
  • Clear: All tasks are cleared at the end of the day, leaving the list empty.

List Comprehensions

List comprehensions in Python offer a concise and powerful way to create and manipulate lists. Instead of using loops to generate or filter elements, you can use list comprehensions to achieve the same result in a single, readable line of code. This feature is particularly useful for applying a specific operation to each element of a list or for filtering elements based on certain conditions. List comprehensions not only make your code shorter but also more expressive and easier to understand.

Here’s a Practical Example of how list comprehension works:

Imagine you’re working on a project that involves analyzing customer reviews for a product. You have a list of review texts, and you want to extract the length of each review to analyze the data further:

# List of customer reviews
reviews = ["Great product!", "Not worth the price.", "Excellent quality, will buy again.", "Average experience.", "Too expensive for what it offers."]

# Using list comprehension to get the length of each review
review_lengths = [len(review) for review in reviews]
print("Lengths of each review:", review_lengths)

Explanation:

List Comprehension: [len(review) for review in reviews] creates a new list, review_lengths, where each element is the length of the corresponding review in the reviews list. This one-liner replaces what would otherwise require multiple lines of code using a loop.

Sorting and Reversing

Sorting and reversing lists in Python help organize data efficiently. Sorting arranges elements in order, while reversing flips their sequence. Python’s `sort()`, `sorted()`, and `reverse()` methods make these tasks simple, useful for displaying or analyzing data in a specific order.

Practical Example:

Imagine you are managing an online store, and you have a list of product prices that you need to sort to display to customers from lowest to highest. Additionally, you might want to reverse the sorted list to show the most expensive items first:

# List of product prices
product_prices = [199.99, 49.99, 299.99, 149.99, 89.99]

# Sort the prices in ascending order
product_prices.sort()
print("Sorted prices (low to high):", product_prices)

# Reverse the list to show the most expensive items first
product_prices.reverse()
print("Prices (high to low):", product_prices)

Explanation:

  • Sorting: product_prices.sort() arranges the prices from the lowest to the highest, making it easier for customers to find affordable products.
  • Reversing: product_prices.reverse() flips the sorted list, showing the most expensive items first, which could be useful for a "luxury items" section

Iterating Through a List

Iterating through a list in Python lets you process each element one by one, ideal for tasks like filtering data or applying calculations. Python’s `for` loop makes it simple to handle each item efficiently.

Practical Example:

Imagine you have a list of customer names, and you want to send a personalized greeting to each:

# List of customer names
customers = ["Alice", "Bob", "Charlie", "Diana"]

# Iterate through the list and print a greeting for each customer
for customer in customers:
print(f"Hello, {customer}! Thank you for your purchase.")

Explanation:
This example demonstrates how you can easily loop through a list of names, sending a personalized message to each customer, which is a common task in customer relationship management.

Nested Lists

Nested lists in Python are lists within lists, allowing you to create complex data structures. This is useful for representing multidimensional data, such as matrices or grids, where each sublist can represent a row or a specific group of related data.

Practical Example:

Imagine you’re managing a seating chart for a theater, with rows and seats:

# Nested list representing seating rows in a theater
seating_chart = [
["Seat1", "Seat2", "Seat3"],
["Seat4", "Seat5", "Seat6"],
["Seat7", "Seat8", "Seat9"]
]

# Accessing a specific seat (Row 2, Seat 2)
print("Selected seat:", seating_chart[1][1])

Explanation:
This example shows how nested lists can represent a seating arrangement, making it easy to access or modify specific seats within different rows.

List Methods ( count, index)

List methods like count and index in Python are essential tools for analyzing and managing lists. The count method lets you determine how many times a specific element appears in a list, while the index method finds the position of the first occurrence of an element.

Practical Example:

Imagine you’re managing a list of students’ names and need to check how often a name appears and where it first occurs:

# List of student names
students = ["Alice", "Bob", "Charlie", "Alice", "Eve", "Alice"]

# Count how many times "Alice" appears
alice_count = students.count("Alice")
print("Alice appears:", alice_count, "times")

# Find the index of the first occurrence of "Charlie"
charlie_index = students.index("Charlie")
print("First occurrence of Charlie is at index:", charlie_index)

Explanation:

  • Count: Determines that “Alice” appears three times in the list.
  • Index: Finds that “Charlie” first appears at index 2.

Copying Lists (Shallow vs. Deep Copy)

Copying lists in Python can be done in two ways: shallow copy and deep copy. Understanding the difference between these two is crucial when working with complex data structures.

  • Shallow Copy: Creates a new list, but elements in the new list are references to the objects found in the original list. Changes to mutable objects in the copied list will affect the original list.
  • Deep Copy: Creates a new list and recursively copies all objects found in the original list, including nested lists. Changes to elements in the copied list do not affect the original list.

Practical Example:

Imagine you’re managing a list of team rosters, with each team containing several players:

import copy

# Original list of teams and players
teams = [["Alice", "Bob"], ["Charlie", "David"], ["Eve", "Frank"]]

# Shallow copy of the teams list
teams_shallow = copy.copy(teams)
# Deep copy of the teams list
teams_deep = copy.deepcopy(teams)

# Modify a player's name in the shallow copy
teams_shallow[0][0] = "Anna"
print("Original list after shallow copy modification:", teams)

# Modify a player's name in the deep copy
teams_deep[1][0] = "Chris"
print("Original list after deep copy modification:", teams)

Explanation:

  • Shallow Copy: When “Alice” is changed to “Anna” in the shallow copy, the change is reflected in the original list because both lists reference the same inner list.
  • Deep Copy: Changing “Charlie” to “Chris” in the deep copy does not affect the original list, as the deep copy created an entirely separate copy of the data.

List Concatenation

List concatenation in Python refers to combining two or more lists into a single list. This can be done using the + operator or the extend() method. Concatenation is useful when you want to merge lists of related items, such as combining different categories of products or merging multiple lists of names.

Practical Example:

Imagine you’re managing two separate lists of fruits and vegetables, and you want to create a single shopping list:

# List of fruits
fruits = ["Apple", "Banana", "Cherry"]

# List of vegetables
vegetables = ["Carrot", "Broccoli", "Spinach"]

# Concatenate the two lists using the + operator
shopping_list = fruits + vegetables
print("Shopping list (using +):", shopping_list)

# Alternatively, you can use the extend() method
fruits.extend(vegetables)
print("Shopping list (using extend):", fruits)

Explanation:

  • Using +: Combines fruits and vegetables into a new list called shopping_list.
  • Using extend(): Adds the contents of vegetables to the end of the fruits list, modifying it directly.

Checking Membership (in, not in)

Checking membership in Python allows you to determine whether a specific element is present in a list (or any other iterable) using the in and not in operators. These operators are handy for verifying if an item exists in a list before performing an action or making decisions based on the presence or absence of an element.

Practical Example:

Imagine you’re creating a guest list for a party and need to check whether certain people are already on the list:

# Guest list for the party
guest_list = ["Alice", "Bob", "Charlie", "Diana"]

# Check if "Alice" is in the guest list
if "Alice" in guest_list:
print("Alice is already on the guest list.")

# Check if "Eve" is not in the guest list
if "Eve" not in guest_list:
print("Eve is not on the guest list. Let's add her.")

Explanation:

  • in: Confirms that "Alice" is already on the guest list, so no action is needed.
  • not in: Detects that "Eve" is not on the guest list, prompting you to add her.

Tuples

A tuple in Python is an ordered, immutable collection of elements, defined using parentheses ().

Mastering Tuples in Python

Difference Between Tuples And Lists

Unlike lists, which are mutable and use square brackets [], tuples cannot be modified after creation, making them ideal for storing data that should remain constant. For example, my_tuple = (1, 2, 3) creates a tuple with three elements.

my_list = [1, 2, 3]   # Mutable list
my_tuple = (1, 2, 3) # Immutable tuple

# Modifying the list
my_list[0] = 10 # This will work because lists are mutable
print(my_list) # Output: [10, 2, 3]

# Modifying the tuple
my_tuple[0] = 10 # This will raise a TypeError because tuples are immutable

When you run the code:

  • The list modification my_list[0] = 10 will succeed, and print(my_list) will output [10, 2, 3].
  • The tuple modification my_tuple[0] = 10 will immediately raise a TypeError, stopping the program and displaying the error message:
TypeError: 'tuple' object does not support item assignment

The program will not proceed beyond the line where the tuple modification is attempted, and you will see the error message in your output.

The implications of immutability

Immutability in Python ensures data integrity by preventing changes to objects, making them safe to use as dictionary keys and in other contexts where stability is essential.

Accessing Tuple Elements

In Python, you can access tuple elements using indexing and slicing, similar to lists. Positive indices retrieve elements from the start (e.g., `0` for the first element), while negative indices count from the end (e.g., `-1` for the last element). Slicing extracts a portion of the tuple by specifying a range.

my_tuple = (10, 20, 30, 40)

# Indexing
print(my_tuple[1]) # Output: 20

# Slicing
print(my_tuple[1:3]) # Output: (20, 30)

# Accessing the last element with negative indexing
print(my_tuple[-1]) # Output: 40

# Accessing the second-to-last element
print(my_tuple[-2]) # Output: 30

Tuple Operations

Tuples in Python support operations like concatenation, repetition, and membership testing. Concatenation combines two tuples into one, repetition creates multiple copies of a tuple, and membership testing checks if an element is present in the tuple using in or not in.

tuple1 = (1, 2, 3)
tuple2 = (4, 5)

# Concatenation
combined_tuple = tuple1 + tuple2 # Output: (1, 2, 3, 4, 5)

# Repetition
repeated_tuple = tuple1 * 2 # Output: (1, 2, 3, 1, 2, 3)

# Membership testing
is_in_tuple = 2 in tuple1 # Output: True
is_not_in_tuple = 4 not in tuple1 # Output: True

Tuple unpacking in Python allows you to assign elements of a tuple to multiple variables in a single statement. This is useful for functions, loops, or when dealing with multiple return values. You can also use the * operator to capture remaining elements into a list.

# Basic tuple unpacking
my_tuple = (1, 2, 3)
a, b, c = my_tuple # a = 1, b = 2, c = 3

# Using the * operator for unpacking
my_tuple = (1, 2, 3, 4, 5)
a, *b, c = my_tuple # a = 1, b = [2, 3, 4], c = 5

Tuple Methods

Tuples have two methods: count() returns the number of times a value appears, and index() gives the first position of a value.

my_tuple = (10, 20, 30, 35, 20)

print(my_tuple.count(20)) # Output: 2
print(my_tuple.index(35)) # Output: 3

Nested tuples

Nested tuples are tuples within tuples. Access elements using multiple indices to navigate the nested structure.

nested_tuple = (1, (2, 3), (4, (5, 6)))

# Accessing nested elements
print(nested_tuple[2][1][1]) # Output: 6

Tuples As Dictionaries

Tuples can be used as dictionary keys because they are immutable, ensuring the keys remain consistent.

I will explain dictionaries in the next section.

# Using tuples as dictionary keys
location_dict = {("Paris", "France"): 2148327, ("Tokyo", "Japan"): 13929286}

# Accessing a value using a tuple key
print(location_dict[("Paris", "France")]) # Output: 2148327

Performance Comparison between Lists and Tuples

Tuples in Python are faster and use less memory than lists due to their immutability, making them ideal for storing fixed, unchangeable data. Use tuples for constant data needing quick access, and lists for mutable collections.

import sys

# Memory comparison
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)

print(sys.getsizeof(my_list)) # Memory size of list eqals 104
print(sys.getsizeof(my_tuple)) # Memory size of tuple eqals 80

Converting Between Tuples and Other Data Structures

Tuples and lists can be easily converted between each other using the tuple() and list() constructors. This allows flexibility in switching between mutable and immutable data structures depending on the needs of your program.

# Converting a list to a tuple
my_list = [1, 2, 3]
my_tuple = tuple(my_list) # Output: (1, 2, 3)

# Converting a tuple to a list
my_tuple = (4, 5, 6)
my_list = list(my_tuple) # Output: [4, 5, 6]

Dictionaries

Uderstanding Dictionaries in Python

Dictionary Basics

A dictionary is an unordered collection of key-value pairs, where each key is unique and maps to a specific value.

my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}
print(my_dict['name']) # Output: Alice

The code above creates a dictionary with key-value pairs and then prints the value associated with the key `’name’`, which is `’Alice’`.

Dictionary Methods

Dictionaries in Python have various built-in methods that allow you to manipulate and interact with key-value pairs effectively.

my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}

# Access a value by key with .get() method
print(my_dict.get('age')) # Output: 25

# Add or update a key-value pair with .update() method
my_dict.update({'age': 26, 'country': 'USA'})
print(my_dict) # Output: {'name': 'Alice', 'age': 26, 'city': 'New York', 'country': 'USA'}

# Remove a key-value pair with .pop() method
age = my_dict.pop('age')
print(age) # Output: 26
print(my_dict) # Output: {'name': 'Alice', 'city': 'New York', 'country': 'USA'}

Explanation:

  • .get('age') retrieves the value associated with the key 'age', which is 25.
  • .update({'age': 26, 'country': 'USA'}) updates the 'age' key to 26 and adds a new key 'country' with the value 'USA'.
  • .pop('age') removes the 'age' key from the dictionary and returns its value, 26.

Dictionary Comprehensions

Dictionary comprehensions provide a concise way to create dictionaries by iterating over an iterable.

# Create a dictionary with numbers as keys and their squares as values
squares = {x: x*x for x in range(6)}

print(squares) # Output: {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

Explanation:

  • The comprehension {x: x*x for x in range(6)} iterates over the numbers 0 to 5, creating a dictionary where each number x is a key, and its square x*x is the corresponding value.

Dictionary Merging

Dictionary merging combines two dictionaries into one, updating or adding new key-value pairs.

dict1 = {'a': 1, 'b': 2}
dict2 = {'b': 3, 'c': 4}

# Merge dict2 into dict1
dict1.update(dict2)

print(dict1) # Output: {'a': 1, 'b': 3, 'c': 4}

Explanation:

  • dict1.update(dict2) merges dict2 into dict1, updating the value of 'b' to 3 and adding a new key 'c' with the value 4.

Nested Dictionaries

Nested dictionaries are dictionaries that contain other dictionaries as their values.

nested_dict = {
'person1': {'name': 'Alice', 'age': 30},
'person2': {'name': 'Bob', 'age': 25}
}

# Access the nested dictionary for 'person1' and then the 'name' key
print(nested_dict['person1']['name']) # Output: Alice

Explanation:

  • The nested dictionary nested_dict contains two keys, 'person1' and 'person2', each mapping to another dictionary that stores details like 'name' and 'age'.
  • nested_dict['person1']['name'] accesses the 'name' value within the nested dictionary for 'person1', which is 'Alice'.

Checking for Keys

You can check if a key exists in a dictionary using the in keyword.

my_dict = {'name': 'Alice', 'age': 25}

# Check if 'age' key exists
if 'age' in my_dict:
print("Key 'age' exists!") # Output: Key 'age' exists!

# Check if 'city' key exists
if 'city' not in my_dict:
print("Key 'city' does not exist!") # Output: Key 'city' does not exist!

Explanation:

The if 'age' in my_dict statement checks if the key 'age' exists in my_dict, and if it does, it prints a confirmation message. Similarly, if 'city' not in my_dict checks for the non-existence of the 'city' key.

Looping Through Dictionaries

You can loop through a dictionary to access keys, values, or key-value pairs.

my_dict = {'name': 'Alice', 'age': 25, 'city': 'New York'}

# Loop through keys
for key in my_dict:
print(key) # Output: name, age, city

# Loop through values
for value in my_dict.values():
print(value) # Output: Alice, 25, New York

# Loop through key-value pairs
for key, value in my_dict.items():
print(f"{key}: {value}")
# Output:
# name: Alice
# age: 25
# city: New York

Explanation:

  • The first loop iterates over the keys of the dictionary, the second loop iterates over the values, and the third loop iterates over key-value pairs, printing each in the format "key: value".

Immutable Keys

Dictionary keys must be immutable, meaning they cannot be changed.

# Valid keys
my_dict = {
'name': 'Alice', # String key
123: 'Number', # Integer key
}

# Invalid key (would raise an error)
# my_dict = {[1, 2, 3]: 'List as key'} # Lists can't be dictionary keys

Explanation:

  • Strings and numbers are valid dictionary keys because they are immutable, but lists are not allowed as keys because they are mutable and can change.

Handling Missing Keys

Accessing a missing key directly raises a KeyError, but using the .get() method avoids this error.

my_dict = {'name': 'Alice', 'age': 25}

# Trying to access a key that doesn't exist (without .get())
# This will raise a KeyError
# print(my_dict['city']) # Uncommenting this line will raise KeyError: 'city'

# Safely access a key that doesn't exist using .get()
print(my_dict.get('city', 'Unknown')) # Output: Unknown

Explanation:

  • Attempting to access my_dict['city'] directly raises a KeyError because the key 'city' does not exist. Using my_dict.get('city', 'Unknown') instead returns 'Unknown' without raising an error.

Performance Considerations

Dictionary operations like lookups, inserts, and deletes are highly efficient, generally with O(1) time complexity due to the underlying hash table implementation.

my_dict = {'name': 'Alice', 'age': 25}

# Lookup operation
print(my_dict['name']) # O(1) time complexity

# Insert operation
my_dict['city'] = 'New York' # O(1) time complexity

# Delete operation
del my_dict['age'] # O(1) time complexity

Explanation:

  • Dictionary operations such as looking up a value (my_dict['name']), inserting a new key-value pair (my_dict['city'] = 'New York'), and deleting a key (del my_dict['age']) are all performed in constant time, O(1), making dictionaries highly efficient for these tasks.

Defaultdict in Python

A regular dictionary raises a KeyError when you try to access a key that doesn't exist. In contrast, a defaultdict automatically provides a default value for any missing key, avoiding the error and making it easier to work with.

# Regular dictionary example
my_dict = {'name': 'Alice', 'age': 25}

# Accessing a non-existent key in a regular dictionary
# This will raise a KeyError
# print(my_dict['city']) # Uncommenting this line will raise KeyError: 'city'

# defaultdict example
from collections import defaultdict

# Create a defaultdict with int as the default factory
my_defaultdict = defaultdict(int)

# Accessing a non-existent key returns the default value (0 in this case)
print(my_defaultdict['count']) # Output: 0

# Increment the value of a key in defaultdict
my_defaultdict['count'] += 1
print(my_defaultdict['count']) # Output: 1

Explanation:

  • In the regular dictionary my_dict, trying to access a non-existent key like 'city' raises a KeyError.
  • In the defaultdict, my_defaultdict, accessing a non-existent key like 'count' automatically returns the default value 0 (since int was used as the default factory) instead of raising an error.

Python Sets

Exploring Sets in Python

Introduction to Python Sets

A Python set is an unordered collection of unique elements. Sets are defined using {} or the set() function. They are useful for membership testing and eliminating duplicates

my_list = [1, 2, 3, 4, 4, 5, 5, 6]
my_set = set(my_list)
print(my_set) # Output: {1, 2, 3, 4, 5, 6}

Explanation

The list my_list contains repeated elements (4 and 5). When converted to a set, my_set removes the duplicates, resulting in {1, 2, 3, 4, 5, 6}.

Creating a set

Sets can be initialized with unique elements or as an empty set using set().

my_set = {1, 2, 3}
empty_set = set()

print(my_set) # Output: {1, 2, 3}
print(empty_set) # Output: set()

Explanation

my_set is created with elements {1, 2, 3}, while empty_set is an empty set created using set().

Set operations

Python sets support operations like union, intersection, difference, and symmetric difference.

set_a = {1, 2, 3}
set_b = {3, 4, 5}

union_set = set_a | set_b # Union: {1, 2, 3, 4, 5}
intersection_set = set_a & set_b # Intersection: {3}
difference_set = set_a - set_b # Difference: {1, 2}
symmetric_diff_set = set_a ^ set_b # Symmetric Difference: {1, 2, 4, 5}

print(union_set)
print(intersection_set)
print(difference_set)
print(symmetric_diff_set)

Explanation

The code performs various set operations:

  • union_set combines all elements from set_a and set_b.
  • intersection_set returns elements common to both sets.
  • difference_set shows elements in set_a but not in set_b.
  • symmetric_diff_set gives elements unique to each set.

Set methods

Common methods include add(), remove(), discard(), pop(), and clear().

my_set = {1, 2, 3}

my_set.add(4) # Adds 4 to the set
my_set.discard(2) # Removes 2 from the set
removed_item = my_set.pop() # Removes a random element from the set
my_set.clear() # Clears the set

print(my_set) # Output: set()

Explanation

The add() method adds 4 to my_set, discard() removes 2, pop() removes a random element, and clear() empties the set.

Frozen sets

A frozenset is an immutable version of a set, meaning its elements cannot be changed after creation.

my_frozenset = frozenset([1, 2, 3, 4])

# Attempting to modify the frozenset
# my_frozenset.add(5) # This will raise an AttributeError

print(my_frozenset) # Output: frozenset({1, 2, 3, 4})

Explanation

frozenset creates an immutable set where elements cannot be added, removed, or altered, making it suitable for use as dictionary keys or elements in other sets.

Set membership testing

Use the in keyword to check if an element exists in a set.

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

print(3 in my_set) # Output: True
print(6 in my_set) # Output: False

Explanation

The in keyword checks whether 3 is in my_set (returns True) and whether 6 is in my_set (returns False).

Iterating through a set

You can iterate over a set using a for loop to access each element.

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

for element in my_set:
print(element)

Explanation

The for loop iterates through each element in my_set, printing them one by one. Since sets are unordered, the elements may appear in any order.

Set comparisons

Sets can be compared using comparison operators to check for subsets, supersets, or equality.

set_a = {1, 2, 3}
set_b = {1, 2, 3, 4, 5}

print(set_a <= set_b) # Output: True (set_a is a subset of set_b)
print(set_b >= set_a) # Output: True (set_b is a superset of set_a)
print(set_a == {1, 2, 3}) # Output: True (sets are equal)

Explanation

The comparison operators check if set_a is a subset of set_b, set_b is a superset of set_a, and whether two sets are equal.

Applications of sets

Sets are commonly used for removing duplicates, membership testing, and performing set operations in data processing.

# Removing duplicates from a list
my_list = [1, 2, 2, 3, 4, 4, 5]
unique_items = set(my_list)
print(unique_items) # Output: {1, 2, 3, 4, 5}

Explanation

By converting a list to a set, duplicate elements are automatically removed, leaving only unique items, which is a common use case for sets in Python.

For more advanced concepts related to Data Structures in Python, such as check out this article:

--

--