Data Structure: List
Revisiting Lists
Let us start with an exercise:
We have a list of fruits:
fruits_list = ["apple", "mango", "grape", "orange"]
And we have the list of their colors:
fruit_colors_list = ["red", "yellow", "purple", "orange"]
-
Objective: Given a fruit, find its color.
fruit = "mango"
-
Step 1: Find the index of the variable fruit in the list fruits
fruit_index = fruits_list.index(fruit)
-
Step 2: Using the index of fruit get its color from the list fruit_colors
fruit_color = fruit_colors_list[fruit_index]
- Step 3: Print fruit and its color.
print(f"Color of {fruit} is fruit_color")
Implmentation:
fruits_list = ["apple", "mango", "grape", "orange"]
fruit_colors_list = ["red", "yellow", "purple", "orange"]
fruit = "mango"
fruit_index = fruits_list.index(fruit)
fruit_color = fruit_colors_list[fruit_index]
print(f"Color of {fruit} is {fruit_color}")
Seems straight forward right?
Lets try again
fruits_list = ["apple", "mango", "grape", "orange"]
fruit_colors_list = ["orange", "yellow", "purple", "red"]
fruit = "apple"
fruit_index = fruits_list.index(fruit)
fruit_color = fruit_colors_list[fruit_index]
print(f"Color of {fruit} is {fruit_color}")
Can you find an error in the above code?* What is it?
fruits_list = ["apple", "mango", "grape", "orange", "cherry"]
fruit_colors_list = ["orange", "yellow", "purple", "red"]
fruit = "cherry"
fruit_index = fruits_list.index(fruit)
fruit_color = fruit_colors_list[fruit_index]
print(f"Color of {fruit} is {fruit_color}")
How about the above code? Can you find an error? What is it?
What if besides color, we wanted to save and fetch other fruit attributes like their taste?
fruits_list = ["apple", "mango", "grape", "orange"]
fruit_colors_list = ["red", "yellow", "purple", "orange"]
fruit_tastes_list = ["crisp", "lush", "sweet-tart", "zesty"]
fruit = "mango"
fruit_index = fruits_list.index(fruit)
fruit_color = fruit_colors_list[fruit_index]
fruit_taste = fruit_tastes_list[fruit_index]
print(f"Color of {fruit} looks {fruit_color} and tastes {fruit_taste}")
What are the drawbacks of using lists? Please discuss with teacher or fellow students?
#What Is a Dictionary in Python?
A Python dictionary stores data as pairs of keys and values:
- A key is a unique identifier used to look up a value.
- A value is the data associated with a key.
This is similar to how a word dictionary works:
- The word (e.g., "Python") is the key.
- The definition of the word (e.g., "a programming language") is the value.
Analogy: Word Dictionary vs Python Dictionary
- Word Dictionary:
-
Key: "Python"
-
Value: "A programming language"
-
Key: "Banana"
-
Value: "A yellow fruit"
- Python Dictionary: In Python, this would look like:
word_dictionary = {
"Python": "A programming language",
"Banana": "A yellow fruit"
}
You can look up the meaning (value) of a word (key):
print(word_dictionary["Python"]) # Output: "A programming language"
print(word_dictionary["Banana"]) # Output: "A yellow fruit"
Key Characteristics of Keys and Values
-
Keys:
- Must be unique: Two entries cannot have the same key.
- Must be immutable: Keys can be strings, numbers, or tuples, but not lists or other mutable objects.
-
Values:
- Can be any data type: Numbers, strings, lists, or even another dictionary.
- Can be duplicated: Multiple keys can have the same value.
Example:
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 85 # Duplicate value is allowed
}
Why Are Dictionaries Useful?
-
Efficient Lookups: Unlike lists where you search by position (index), dictionaries allow you to quickly access data by its key.
-
Unstructured Data: Dictionaries are great for representing data where items have labels or names instead of just positions.
Practical Example: Phone Book
Let’s create a simple phone book using a dictionary:
phone_book = {
"Alice": "123-456-7890",
"Bob": "987-654-3210",
"Charlie": "555-555-5555"
}
- Key: Name of the person (e.g., "Alice")
- Value: Phone number (e.g., "123-456-7890")
To find Bob’s number:
bobs_number = phone_book["Bob"]
print(bobs_number) # Output: 987-654-3210
Key vs. Value in Context
- Key: The "word" or "identifier" used to find something.
- Example: "Bob" in the phone book, or "Banana" in the word dictionary.
- Value: The actual information stored and retrieved using the key.
- Example: "987-654-3210" for Bob, or "A yellow fruit" for Banana.
Summary
A Python dictionary is like a word dictionary:
- Keys are the words you look up (unique identifiers).
- Values are the definitions or associated information.
Python makes it easy to access, modify, and manage this key-value pair relationship efficiently, making dictionaries one of the most powerful data structures.
Working with dictionaries in Python
##1. Creating an Empty Dictionary
We can create an empty dictionary in two ways:
-
Method 1: Using curly braces
empty_dict = {}
print(empty_dict) # Output: {} -
Method 2: Using the dict() function
empty_dict = dict()
print(empty_dict) # Output: {}
Creating a Non-Empty Dictionary
A dictionary with initial key-value pairs can be created like this:
# Example: Storing names and ages
person_info = {"Alice": 25, "Bob": 30, "Charlie": 35}
print(person_info) # Output: {'Alice': 25, 'Bob': 30, 'Charlie': 35}
2. Adding Key-Value Pairs to a Dictionary
We can add a new key-value pair to a dictionary by assigning a value to a new key:
Add a new key-value pair
person_info = {"Alice": 25, "Bob": 30, "Charlie": 35}
print(person_info) # Output: {'Alice': 25, 'Bob': 30, 'Charlie': 35}
person_info["David"] = 40
print(person_info) # Output: {'Alice': 25, 'Bob': 30, 'Charlie': 35, 'David': 40}
3. Accessing Values Using Keys
We can retrieve a value by using the key in square brackets:
person_info = {"Alice": 25, "Bob": 30, "Charlie": 35}
# Access Bob's age
bob_age = person_info["Bob"]
print(f"Bob's age: {bob_age}") # Output: Bob's age: 30
4. Modifying Values Using Keys
person_info = {"Alice": 25, "Bob": 30, "Charlie": 35}
alice_age = person_info["Alice"]
print(f"Alice's age: {alice_age}") # Output: Bob's age: 25
# Update Alice's age
person_info["Alice"] = 26 #We are modifying Alice's age to 26
alice_age = person_info["Alice"]
print(f"Alice's age: {alice_age}") # Output: Bob's age: 26
5. Deleting a Key-Value Pair
We can delete a key-value pair using the del statement or the pop() method:
person_info = {"Alice": 25, "Bob": 30, "Charlie": 35}
print(person_info) #Output: {'Alice': 25, 'Bob': 30, 'Charlie': 35}
del person_info["Charlie"] #Deleting Charlie
print(person_info) #Output: {'Alice': 25, 'Bob': 30}
Summary of dictionary operations
-
- Empty Dictionary: empty_dict = or empty_dict = dict()
-
- Non-Empty Dictionary: my_dict =
{"key1": "value1", "key2": "value2"}
- Non-Empty Dictionary: my_dict =
-
- Add a Key-Value Pair: my_dict["new_key"] = "new_value"
-
- Access a Value: my_dict["key"] or my_dict.get("key", "default")
-
- Modify a Value: my_dict["key"] = "updated_value"
-
- Delete a Key: del my_dict["key"]
Now that we have understood what dictionaries are and how they work, lets practice:
###1. Create a Contact Book Write a program to create an empty dictionary and add contacts to it. Each contact should have a name (key) and a phone number (value).
Problem Statement:
- Create an empty dictionary.
- Add 3 contacts: Alice - 12345, Bob - 67890, Charlie - 54321.
- Retrieve and print Bob's phone number.
- Modify Alice's phone number to 11111.
- Delete Charlie from the contact book.
- Print the updated contact list
#Problem 1: Write code here
contact_list = {} #Empty dictionary
###2. Grocery Inventory
Manage a grocery store's inventory using a dictionary. Each key is an item name, and the value is the quantity in stock.
Problem Statement:
- Start with an empty dictionary.
- Add 3 items: Apples - 10, Bananas - 20, Oranges - 15.
- Retrieve and print the quantity of Bananas.
- Update the quantity of Apples to 5.
- Remove Oranges from the inventory.
- Print updated grocery list
#Problem 2: Write code here
grocery_inventory = {} #Empty dictionary
Problem 3. Fix the code
Fix the code so Charlie and Alice's favorite movies are printed correctly
# Initialize the dictionary
favorite_movies = { "Alice": "Inception", "Bob": "Titanic" }
# Add a new person
favorite_movies["Charlie"] = "Interstellar"
print("Charlie's favorite movie is:", favorite_movies["charlie"])
# Modify Bob's favorite movie
favorite_movies["Bob"] = "Avatar"
del favorite_movies["Alice"]
print("Alice's favorite movie is:", favorite_movies["Alice"])
###Problem 4: Employee salaries (Part 1)
Objectives:
- Add code to calculated the total salary of all employees
- Print "Total Salary: 165000" #Do not hard code
employee_salaries = {"Alice": 50000, "Bob": 60000}
# Add a new employee
employee_salaries["Charlie"] = 55000
###Problem 4: Employee salaries (Part 2)
Objectives:
- Add code to calculated the average salary of employees
- Print "Average Salary: 55000" #Do not hard code
employee_salaries = {"Alice": 50000, "Bob": 60000}
Problem5: Movie Ratings
Objectives:
- Find and print the name of the movie with highest rating
movie_ratings = {"Inception": 9.0, "Titanic": 8.5}
Create, modify, access and delete: Operations That Require Knowing the Key
So far we have learnt how to create, modify, access and delete from a dictionary using keys. All these basic methods require us to the key in advance.
If we do not know what key or we have the wrong key these operations will not work.
Let me explain with the help of an example:
Example: Known Key
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 78
}
# Access a value using a known key
print(student_grades["Alice"]) # Output: 85
# Modify a value using a known key
student_grades["Bob"] = 95
print(student_grades["Bob"]) # Output: 95
# Delete an entry using a known key
del student_grades["Charlie"]
print(student_grades) # Output: {'Alice': 85, 'Bob': 95}
# Delete an entry using a known key
del student_grades["Charlie"]
print(student_grades) # Output: {'Alice': 85, 'Bob': 95}
What Happens When the Key Is Unknown or Wrong
If we attempt to perform operations using a key that doesn’t exist in the dictionary, Python raises a KeyError.
Example: Missing Key
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 78
}
# Trying to access a value with a missing key
print(student_grades["David"]) # KeyError: 'David'
# Trying to delete a key that doesn’t exist
del student_grades["Eve"] # KeyError: 'Eve'
Introducing Iteration
Iteration allows us to systematically loop through the dictionary to access its keys, values, or key-value pairs without needing to know the keys in advance.
Example: Basic Iteration
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 78
}
# Iterate over all keys
for key in student_grades:
print(f"{key}: {student_grades[key]}")
# Output:
# Alice: 85
# Bob: 90
# Charlie: 78
Types of Iteration
##1. Iterate Over Keys
This is the default behavior when you use a for loop directly on the dictionary.
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 78
}
for key in student_grades:
print(f"Key: {key}")
# Output:
# Key: Alice
# Key: Bob
# Key: Charlie
2. Iterate Over Values
Use the .values() method to loop through the dictionary’s values.
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 78
}
for value in student_grades.values():
print(f"Value: {value}")
# Output:
# Value: 85
# Value: 90
# Value: 78
3. Iterate Over Key-Value Pairs
Use the .items() method to loop through key-value pairs as tuples.
student_grades = {
"Alice": 85,
"Bob": 90,
"Charlie": 78
}
for key, value in student_grades.items():
print(f"{key} has a grade of {value}")
# Output:
# Alice has a grade of 85
# Bob has a grade of 90
# Charlie has a grade of 78
Understanding Iteration
Iteration is the process of accessing each item in a collection (e.g., a dictionary, list, or set) one at a time, typically using a loop. In Python, iteration is often done using a for loop.
When you iterate over a dictionary, you can loop through its:
- Keys (default behavior),
- Values,
- Key-Value Pairs.
Practicing iteration
Problem 1: Write a program to print students names and their grade.
Expected output:
Alice: 85
Bob: 90
Charlie: 78
student_grades = {"Alice": 85, "Bob": 90, "Charlie": 78}
Problem 2: Print the total number of students and the number of students with grade A.
Expected output:
Total students: 10
Total students with grade A: 4
student_grades = {
"Alice": "A",
"Bob": "C",
"Charlie": "C",
"David": "B",
"Eve": "A",
"Frank": "B",
"Grace": "C",
"Hannah": "A",
"Isaac": "B",
"Jack": "A"
}
#Start your code here
Problem 3: Print student names with grade B or above
Expected output:
Students with grade B or above:
Alice
David
Eve
Frank
Hannah
Isaac
Jack
student_grades = {
"Alice": "A",
"Bob": "C",
"Charlie": "C",
"David": "B",
"Eve": "A",
"Frank": "B",
"Grace": "C",
"Hannah": "A",
"Isaac": "B",
"Jack": "A"
}
#Start your code here
Problem 4: Create a dictionary from a list of numbers from 1 to 10, where each number is a key and its value is either 'even' or 'odd', based on whether the number is even or odd.
Expected outout:
{1: 'odd', 2: 'even', 3: 'odd', 4: 'even', 5: 'odd', 6: 'even', 7: 'odd', 8: 'even', 9: 'odd', 10: 'even'}
#Write your code here
Problem 5: Using the dictionary student_grades, remove all students with grade of C and print student_grades
Expected outout:
{
"Alice": "A",
"David": "B",
"Eve": "A",
"Frank": "B",
"Hannah": "A",
"Isaac": "B",
"Jack": "A"
}
student_grades = {
"Alice": "A",
"Bob": "C",
"Charlie": "C",
"David": "B",
"Eve": "A",
"Frank": "B",
"Grace": "C",
"Hannah": "A",
"Isaac": "B",
"Jack": "A"
}
#Write your code here
List of Dictionaries - Nested Data Structures
A list of dictionaries is a powerful data structure in Python that allows you to store multiple dictionaries inside a list. It is often used to represent a collection of structured data, where each dictionary contains key-value pairs describing an item.
So far we have been using a simple dictionary with key value pair to store keys and associated values:
student_grades = {
"Alice": "A",
"Bob": "C",
"Charlie": "C",
"David": "B",
"Eve": "A",
"Frank": "B",
"Grace": "C",
"Hannah": "A",
"Isaac": "B",
"Jack": "A"
}
If along with student grades we also need to store student ages. We will have to create a new data dictionary:
student_ages = {
"Alice": 20,
"Bob": 21,
"Charlie": 22,
"David": 23,
"Eve": 20,
"Frank": 21,
"Grace": 22,
"Hannah": 19,
"Isaac": 24,
"Jack": 20
}
If we also need to store students' majors we will need one more dictionary.
student_majors = {
"Alice": "Physics",
"Bob": "History",
"Charlie": "Chemistry",
"David": "Computer Science",
"Eve": "Mathematics",
"Frank": "Art",
"Grace": "Biology",
"Hannah": "Environmental Science",
"Isaac": "English",
"Jack": "Philosophy"
}
Having multiple dictionaries for each attribute, like student_grades, student_ages, and student_majors, can quickly become cumbersome and error-prone when dealing with real-world scenarios. Here's why:
1. Complexity of Searching
When we need to retrieve information about a specific student (e.g., their grade, age, and major), we have to perform lookups across multiple dictionaries:
Example:
student_name = "Alice"
grade = student_grades.get(student_name)
age = student_ages.get(student_name)
major = student_majors.get(student_name)
print(f"{student_name}: Grade = {grade}, Age = {age}, Major = {major}")
Problems:
- Multiple Lookups: For every attribute, we need to search a separate dictionary.
- Data Syncing Issues: If one dictionary is updated but another isn’t, inconsistencies arise.
- Performance Overhead: Searching multiple dictionaries takes more time and resources.
2. Inserting a New Student
Adding a new student requires inserting data into multiple dictionaries:
Example:
new_student = "John"
student_grades[new_student] = "B"
student_ages[new_student] = 21
student_majors[new_student] = "Physics"
Problems:
- Error-Prone: Forgetting to add the student to one of the dictionaries can cause incomplete data.
- Inconsistent State: If one dictionary is updated but another is not, the data becomes unreliable.
- Tedious Maintenance: Every insertion operation involves three separate steps, making the code repetitive and harder to maintain.
3. Updating an Existing Student
To update a student's information (e.g., changing their major), we must update the correct key in the appropriate dictionary:
Example:
student_name = "Alice"
student_grades[student_name] = "A+"
student_ages[student_name] = 21
student_majors[student_name] = "Mathematics"
Problems:
- Manual Effort: Updating multiple dictionaries is tedious.
- Risk of Mistakes: It's easy to miss one update or update the wrong dictionary, causing inconsistent data.
4. Limited Extensibility
If we want to add a new attribute (e.g., GPA), you need to create yet another dictionary:
student_gpa = {
"Alice": 3.9,
"Bob": 3.2,
# etc.
}
Here's an example of why having multiple dictionaries to save related data can be hard to maintain and troubleshoot
#Initial Dictionaries
# Separate dictionaries for student attributes
student_grades = {
"Alice": "A",
"Bob": "C",
"Charlie": "C",
}
student_ages = {
"Alice": 20,
"Bob": 21,
# "Charlie" is missing here!
}
student_majors = {
"Alice": "Physics",
"Bob": "History",
"Charlie": "Chemistry",
}
#Accessing All Information for a Student
# Function to retrieve a student's complete information
def get_student_info(name):
grade = student_grades[name]
age = student_ages[name] # This will throw a KeyError if `name` is missing
major = student_majors[name]
return {"name": name, "grade": grade, "age": age, "major": major}
# Retrieve data for each student
for student in student_grades.keys():
info = get_student_info(student)
if info:
print(info)
Better Approach: Using a List of Dictionaries
A list of dictionaries solves these issues by storing all attributes for a student in one dictionary. This makes searching, inserting, updating, and extending attributes much simpler and more reliable.
Example Structure:
students = [
{"name": "Alice", "grade": "A", "age": 20, "major": "Physics"},
{"name": "Bob", "grade": "C", "age": 21, "major": "History"},
{"name": "Charlie", "grade": "C", "age": 22, "major": "Chemistry"}
]
Advantages of List of Dictionaries
- Unified Storage:
- Each student’s information is stored in a single dictionary, reducing fragmentation.
- Simpler Search:
- Searching for a student involves iterating over a single list:
student_name = "Alice"
student = next((s for s in students if s["name"] == student_name), None)
if student:
print(student) # {'name': 'Alice', 'grade': 'A', 'age': 20, 'major': 'Physics'}
- Simpler Insertions:
- Adding a new student requires just one step:
students.append({"name": "John", "grade": "B", "age": 21, "major": "Physics"})
- Simpler Updates:
- Updating a student involves modifying a single dictionary:
for student in students:
if student["name"] == "Alice":
student["grade"] = "A+"
student["major"] = "Mathematics"
##How to Search a List of Dictionaries in Python
Searching a list of dictionaries is a common task when working with structured data. In Python, this typically involves iterating through the list and checking each dictionary for a matching key-value pair.
Basic Steps to Search
- Understand the Structure
A list of dictionaries contains multiple dictionaries, each with key-value pairs.
- Define the Search Criteria
Determine which key and value you want to search for.
- Iterate Through the List
Use a loop to check each dictionary in the list for the desired value. 4. Handle Results
Return or print the matching dictionary if found, or indicate if no match exists.
Example: Searching for a Student by Name
Data Structure
We will use a list of dictionaries where each dictionary represents a student:
students = [
{"name": "Alice", "grade": "A", "age": 20, "major": "Physics"},
{"name": "Bob", "grade": "B", "age": 21, "major": "History"},
{"name": "Charlie", "grade": "C", "age": 22, "major": "Chemistry"}
]
Task
Search for a student by their name and return their details.
def search_student_by_name(students, search_name):
# Convert search name to lowercase for case-insensitive comparison
search_name = search_name.lower()
# Iterate through the list of dictionaries
for student in students:
if student["name"].lower() == search_name: # Case-insensitive match
return student # Return the matching dictionary
# If no match is found, return None
return None
# Example Usage
search_name = input("Enter the name of the student you want to search for: ")
result = search_student_by_name(students, search_name)
if result:
print("Student found:", result)
else:
print("Student not found.")
1. Creating list of dictionary
- Create a Python list called students.
- Add 3 dictionaries to this list, each representing a student.
- Each dictionary should have the following attributes:
- name: Student’s name.
- grade: Student’s grade.
- age: Student’s age.
- Print the list of dictionary created above
#Write your code here
2. Updating list of dictionary: Adding a new attribute
Please enhance the exercise above by adding the below use case:
- For each student, prompt the user to provide a major.
Example:
"Please provide major for Alice:"
- Update the Dictionary:
Add the user-provided major to the respective student's dictionary.
- Print the Updated List:
After updating all students, print the list of dictionaries to display the updated student records.
#Write your code here
##3. Insertint into the list: Adding a New Student
Building on the previous exercise where the list of students was updated with their major, let's enhance the program to allow the user to add a new student by providing the following details via prompts:
- Name: Prompt the user for the new student’s name.
- Age: Prompt the user for the new student’s age.
- Grade: Prompt the user for the new student’s grade.
- Major: Prompt the user for the new student’s major.
Example:
Enter the new student's name: Diana
Enter Diana's age: 23
Enter Diana's grade: A
Enter Diana's major: Computer Science
After collecting the details, create a new dictionary for the student and add it to the students list. Finally, print the updated list of students.
Expected Output:
[
{"name": "Diana", "grade": "A", "age": 23, "major": "Computer Science"}
]
4. Searching the list of dictionary: Fine a student by Name
Write a program to search for a student in the students list of dictionaries by their name. The program should:
- Prompt the User:
Ask the user to input the name of the student they want to search for.
- Perform the Search:
Iterate through the students list and check if the name attribute matches the user input (case-insensitive).
- Display the Results:
If the student is found, print the student’s details (name, age, grade, and major).
If the student is not found, print a message saying "Student not found."