
6 Data structures

In Chapter 2, we learned about primitive data types, each of which represents a single value.
In this chapter, we will explore container data types, also known as data structures or collection data types in Python. These data types allow us to store multiple primitive values, such as integers, booleans, and strings, as well as objects of different data types, all within a single structure.
String is one type of container data type, consisting of a sequence of characters. You already learned about strings in previous chapters. In this chapter, we focus on four main container data types in Python: list, tuple, set, and dictionary. Each differs in terms of order and immutability:
- List: Ordered and mutable (elements can be changed).
- Tuple: Ordered and immutable (elements cannot be changed once defined).
- Set: Unordered and mutable (elements can be added or removed, but duplicates are not allowed).
- Dictionary: Ordered (as of Python 3.7) and mutable, with key-value pairs for efficient lookups.
We will explore their characteristics, use cases, and differences in detail in this chapter.
6.1 Lists
A List in Python is an ordered, mutable (changeable) collection of items. Lists are one of the most versatile data structures in Python.
6.1.1 Creating a List
You can create a list by enclosing items in square brackets, separated by commas:
# Creating lists
= []
empty_list = [1, 2, 3, 4, 5]
numbers = [42, "hello", True, 3.14] mixed
6.1.2 Accessing Elements
Lists are ordered collections with unique indexes for each item. We can access/slice the items in the list using this index number. Python supports both positive and negative indexing, as shown below:
- Indexing: Use
[index]
to access a specific item. - Slicing: Use
[start:end:step]
to get a sub-list.
= [10, 20, 30, 40, 50]
my_list
print(my_list[0]) # 10
print(my_list[-1]) # 50
print(my_list[1:3]) # [20, 30]
print(my_list[2:]) # [30, 40, 50]
print(my_list[-3:-1]) # [30, 40]
print(my_list[::2]) # [10, 30, 50] (step of 2)
print(my_list[::-1]) # [50, 40, 30, 20, 10] (reverse)
10
50
[20, 30]
[30, 40, 50]
[30, 40]
[10, 30, 50]
[50, 40, 30, 20, 10]
6.1.3 Modifying a List
Lists can be changed after creation. You can add, remove, or replace elements.
6.1.3.1 Adding Items
append(item)
: Add item at the end.insert(index, item)
: Insert item at a specific index.extend(iterable)
: Extend the list by appending all items from an iterable (like another list).
= ["apple", "banana"]
fruits "cherry")
fruits.append(print(fruits)
1, "orange")
fruits.insert(print(fruits)
"grape", "mango"])
fruits.extend([print(fruits)
['apple', 'banana', 'cherry']
['apple', 'orange', 'banana', 'cherry']
['apple', 'orange', 'banana', 'cherry', 'grape', 'mango']
Lists can be also concatenated using the +
operator:
= [5,'hi',4]
list_example = list_example + [None,'7',9]
list_example list_example
[5, 'hi', 4, None, '7', 9]
For adding elements to a list, the extend
method is preferred over the +
operator. This is because the +
operator creates a new list, while the extend
method adds elements to an existing list. Thus, the extend
operator is more memory efficient.
6.1.3.2 Removing Items
pop([index])
: Removes and returns the item at index. If no index is given, removes the last item.remove(value)
: Removes the first occurrence of value.clear()
: Removes all items from the list, making it empty.
= [10, 20, 30, 40, 50]
numbers
= numbers.pop()
last_item print(last_item)
print(numbers)
20)
numbers.remove(print(numbers)
numbers.clear()print(numbers)
50
[10, 20, 30, 40]
[10, 30, 40]
[]
6.1.3.3 Replacing Items
You can directly reassign an element using the index:
= ["a", "b", "c", "d"]
letters 1] = "z"
letters[print(letters)
['a', 'z', 'c', 'd']
6.1.3.4 my_list.sort()
— Sorts in place
Modifies the original list directly
Returns
None
Only works on lists
= [4, 1, 3, 2]
nums
nums.sort()print(nums)
[1, 2, 3, 4]
📌 Python Design Philosophy
This is based on a common Python design principle:
“Mutating methods should return
None
to make it clear that they operate in place.”
This discourages writing things like:
= my_list.sort() # ❌ This will result in None sorted_list
= nums.sort()
sorted_list print(sorted_list) # None, because sort() modifies the list in place
None
By default, list.sort()
sorts the list in ascending order. You can also pass a reverse=True
argument to sort()
to reverse the order:
=True)
nums.sort(reverseprint(nums)
[4, 3, 2, 1]
help(list.sort)
Help on method_descriptor:
sort(self, /, *, key=None, reverse=False) unbound builtins.list method
Sort the list in ascending order and return None.
The sort is in-place (i.e. the list itself is modified) and stable (i.e. the
order of two equal elements is maintained).
If a key function is given, apply it once to each list item and sort them,
ascending or descending, according to their function values.
The reverse flag can be set to sort in descending order.
You can also set the key
parameter to a function that returns a value to sort by:
Example 1: Sorting strings by their length:
We define a function get_length
that returns the length of a string. Then, we use this function as the key
in the sort method.
def get_length(s):
return len(s)
= ["apple", "banana", "kiwi", "grape", "pineapple"]
words =get_length) # Sorts by string length
words.sort(keyprint("Sorted by length:", words)
Sorted by length: ['kiwi', 'apple', 'grape', 'banana', 'pineapple']
Another way to achieve it. If a key function is given, apply it once to each list item and sort them, ascending or descending, according to their function values.
the len
function will be applied to each list item.
=len, reverse=True) # Sorts by string length in reverse
words.sort(keyprint("Sorted by length:", words)
Sorted by length: ['pineapple', 'banana', 'apple', 'grape', 'kiwi']
Another way to define the key function is by using a lambda
function. The concept of lambda
functions will be covered in the later sequence course.
# use lambada function
=lambda s: s[-1]) # Sorts by last letter
words.sort(keyprint("Sorted by last letter:", words)
Sorted by last letter: ['banana', 'pineapple', 'apple', 'grape', 'kiwi']
Example 2: Sorting a List of Lists by a given Element
def sort_by_index(data, i):
def get_element(lst):
return lst[i] # Extract the element at index i
=get_element) # Sort by the specified index
data.sort(key
# Example usage:
= [[1, 5, 9], [3, 2, 8], [4, 8, 6], [2, 6, 7]]
data
# Sort by the second element (index 1)
1)
sort_by_index(data, print("Sorted by index 1:", data)
# Sort by the third element (index 2)
2)
sort_by_index(data, print("Sorted by index 2:", data)
Sorted by index 1: [[3, 2, 8], [1, 5, 9], [2, 6, 7], [4, 8, 6]]
Sorted by index 2: [[4, 8, 6], [2, 6, 7], [3, 2, 8], [1, 5, 9]]
Let’s use lambda
function to rewrite it
=lambda lst: lst[0] + lst[1] + lst[2]) # Sort by sum of elements
data.sort(keyprint("Sorted by sum:", data)
# sort by the last element in descending order
=lambda lst: lst[-1], reverse=True)
data.sort(keyprint("Sorted by last element in descending order:", data)
Sorted by sum: [[3, 2, 8], [2, 6, 7], [1, 5, 9], [4, 8, 6]]
Sorted by last element in descending order: [[1, 5, 9], [3, 2, 8], [2, 6, 7], [4, 8, 6]]
6.1.3.5 sorted(my_list)
— Returns a new sorted list
Does not modify the original list
Works with any iterable (not just lists)
Can be used with
key
andreverse
parametersUseful when you want to keep the original list unchanged
= [3, 1, 4, 1, 5]
numbers = sorted(numbers)
sorted_numbers print(sorted_numbers) # Output: [1, 1, 3, 4, 5]
[1, 1, 3, 4, 5]
= [3, 1, 4, 1, 5]
numbers = sorted(numbers, reverse=True)
sorted_numbers print(sorted_numbers) # Output: [5, 4, 3, 1, 1]
[5, 4, 3, 1, 1]
= "python"
word = sorted(word)
sorted_chars print(sorted_chars) # Output: ['h', 'n', 'o', 'p', 't', 'y']
['h', 'n', 'o', 'p', 't', 'y']
The key
parameter allows customization of sorting logic by applying a function to each element before comparison.
= ["banana", "apple", "cherry"]
words = sorted(words, key=len)
sorted_words print(sorted_words) # Output: ['apple', 'banana', 'cherry']
['apple', 'banana', 'cherry']
= [-5, 3, -1, 7]
numbers = sorted(numbers, key=abs)
sorted_numbers print(sorted_numbers) # Output: [-1, 3, -5, 7]
[-1, 3, -5, 7]
# uncomment the line below to see the error
sorted(["apple", "orange", 32])
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[23], line 3 1 #| eval: false 2 # uncomment the line below to see the error ----> 3 sorted(["apple", "orange", 32]) TypeError: '<' not supported between instances of 'int' and 'str'
When you use functions like sorted
on an iterable, Python will try to perform comparisons or arithmetic operations between the elements. These functions work seamlessly when all elements are of types that can be compared or added together. However, if the iterable contains mixed types that are not inherently comparable (like strings and numbers), you’ll run into errors.
By ensuring the elements in your iterable are of compatible types, you can effectively use these functions without encountering runtime errors.
6.1.3.6 Difference Between sorted()
and list.sort()
Feature | sorted() |
list.sort() |
---|---|---|
Return Value | Returns a new sorted list | Modifies the list in place and returns None . |
Input Type | Works with any iterable (e.g., lists, tuples, strings). | Works only with lists. |
Usage | sorted(iterable) |
list.sort() |
Example:
= [3, 1, 2]
my_list
# Using sorted()
= sorted(my_list)
new_list print("Original List:", my_list) # [3, 1, 2]
print("New Sorted List:", new_list) # [1, 2, 3]
# Using list.sort()
my_list.sort()print("List after list.sort():", my_list) # [1, 2, 3]
Original List: [3, 1, 2]
New Sorted List: [1, 2, 3]
List after list.sort(): [1, 2, 3]
6.1.3.7 Other Useful Methods
reverse()
: Reverses the list in place.index(value)
: Returns the index of the first occurrence of value.
nums.reverse()print(nums)
= nums.index(3)
idx print(idx)
[1, 2, 3, 4]
2
help(list.reverse)
Help on method_descriptor:
reverse(self, /) unbound builtins.list method
Reverse *IN PLACE*.
6.1.3.8 In-Place vs. Out-of-Place Operations
Note that both list.sort()
and list.reverse()
modify the list in place, meaning they do not create a new list but instead change the original one directly. To sort or reverse a list without modifying the original list in place, you can use functions that create a new list rather than updating the existing one:
Sorting Without In-Place Modification:
= [3, 1, 2]
original_list = sorted(original_list) # returns a new, sorted list
sorted_list print(original_list) # [3, 1, 2] (unchanged)
print(sorted_list) # [1, 2, 3]
[3, 1, 2]
[1, 2, 3]
Reversing Without In-Place Modification:
# method 1: use the built-in reversed function
= [3, 1, 2]
original_list = list(reversed(original_list))
reversed_list print(original_list) # [3, 1, 2] (unchanged)
print(reversed_list) # [2, 1, 3]
[3, 1, 2]
[2, 1, 3]
# use list slicing ([::-1]) to create a reversed copy of the original list
= [3, 1, 2]
original_list = original_list[::-1]
reversed_list print(original_list) # [3, 1, 2] (unchanged)
print(reversed_list) # [2, 1, 3]
[3, 1, 2]
[2, 1, 3]
6.1.4 Practice exercise 1
Start by defining a list that contains the elements [8, 9, 10]. Then do the following:
6.1.4.1
Set the second entry (index 1) to 17
6.1.4.2
Add 4, 5, and 6 to the end of the list
6.1.4.3
Remove the first entry from the list
6.1.4.4
Sort the list
6.1.4.5
Double the list (concatenate the list to itself)
6.1.4.6
Insert 25 at index 3
, then print the final list.
Expected Output: [4, 5, 6, 25, 10, 17, 4, 5, 6, 10, 17]
6.1.5 List Comprehension
List comprehension is a concise and elegant way to create lists in Python. It provides a shorter syntax to generate lists based on existing iterables while applying conditions or transformations.
Basic Syntax
[expression for item in iterable if condition]
Components:
- Expression: The value or transformation applied to each item.
for
item in iterable: Iterates over the iterable (e.g., list, range, string).- Condition (optional): Filters items based on a condition.
Examples:
- Simple List Comprehension
# create a list of squares of numbers from 1 to 5
= [x**2 for x in range(1, 6)]
squares print(squares)
[1, 4, 9, 16, 25]
- List Comprehension with Condition
# create a list of even numbers from 1 to 10
= [x for x in range(1, 11) if x % 2 == 0]
evens print(evens) # Output: [2, 4, 6, 8, 10]
[2, 4, 6, 8, 10]
- List Comprehension with Transformation
# create a list of words with all letters in uppercase
= ["hello", "world", "python"]
words = [word.upper() for word in words]
uppercase_words print(uppercase_words)
['HELLO', 'WORLD', 'PYTHON']
- Nested List Comprehension
# flatten a 2D matrix into a 1D list
= [[1, 2], [3, 4], [5, 6]]
matrix = [num for row in matrix for num in row]
flattened print(flattened) # Output: [1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
Anything that can be accomplished using list comprehension can also be achieved with traditional Python loops. However, list comprehension often reduces the amount of code, making it more concise and readable. Additionally, it is often faster than equivalent for loops due to Python’s optimized implementation.
Comparison with for
loops
# using a for loop
= []
squares for x in range(1, 6):
**2)
squares.append(xprint(squares)
[1, 4, 9, 16, 25]
# using list comprehension
= [x**2 for x in range(1, 6)]
squares print(squares)
Both achieve the same result, but the list comprehension is more concise.
6.1.6 Practice exercise 2
Using list comprehension:
- Create a list of all odd numbers between 1 and 20.
- Generate a list of the lengths of each word in the list [“apple”, “banana”, “cherry”].
- Create a list of numbers divisible by both 3 and 5 from 1 to 100.
6.2 Tuples
A Tuple is an ordered, immutable (unchangeable) collection of items. Tuples can be thought of as lists that cannot be modified after creation.
6.2.1 Creating a Tuple
Use parentheses or the tuple()
constructor.
= (1, 2, 3)
my_tuple = "apple", "banana", "cherry" # Parentheses are optional
another_tuple = ("hello",) # Note the trailing comma
single_item_tuple
= tuple([4, 5, 6]) # Using tuple() constructor converted_tuple
6.2.2 Accessing Elements
Indexing and slicing work similarly to lists:
= (10, 20, 30, 40, 50)
t
print(t[0]) # 10
print(t[1:3]) # (20, 30)
10
(20, 30)
6.2.3 Immutability
Once you create a tuple, you cannot modify it:
= (1, 2, 3)
t 0] = 10 t[
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[38], line 3 1 #| eval: false 2 t = (1, 2, 3) ----> 3 t[0] = 10 TypeError: 'tuple' object does not support item assignment
Tuple can be defined without the rounded brackets as well:
If you need to change elements, convert it to a list, modify the list, and convert back to a tuple (though this somewhat defeats the purpose of immutability).
6.2.4 Tuple methods
A couple of useful tuple methods are count
, which counts the occurences of an element in the tuple and index
, which returns the position of the first occurance of an element in the tuple:
= (2,5,64,7,2,2) tuple_example
2) tuple_example.count(
3
2) tuple_example.index(
0
6.2.5 Concatenating tuples
Tuples can be concatenated using the + operator to produce a longer tuple:
2,7,4) + ("another", "tuple") + ("mixed","datatypes",5) (
(2, 7, 4, 'another', 'tuple', 'mixed', 'datatypes', 5)
Multiplying a tuple by an integer results in repetition of the tuple:
2,7,"hi") * 3 (
(2, 7, 'hi', 2, 7, 'hi', 2, 7, 'hi')
6.2.6 Why Use a Tuple?
A list seems to be much more flexible than tuple, and can replace a tuple almost everywhere. Then why use tuple at all?
Some of the advatages of a tuple over a list are as follows:
- Data Integrity: Tuples ensure the data cannot be modified accidentally.
- Faster: Tuples can be more memory efficient and faster to iterate over compared to lists.
- Dictionary Keys: Tuples can be used as keys in dictionaries (because they are immutable).
#Example showing tuples take less storage space than lists for the same elements
= (1, 2, 'Obama')
tuple_ex = [1, 2, 'Obama']
list_ex print("Space taken by tuple =",tuple_ex.__sizeof__()," bytes")
print("Space taken by list =",list_ex.__sizeof__()," bytes")
Space taken by tuple = 48 bytes
Space taken by list = 72 bytes
#Examples showing tuples takes lesser time to retrieve elements
import time as tm
= tm.time()
tt = list(range(1000000)) #List containinig whole numbers upto 1 million
list_ex =(list_ex[::-2])
aprint("Time take to retrieve every 2nd element from a list = ", tm.time()-tt)
= tm.time()
tt = tuple(range(1000000)) #tuple containinig whole numbers upto 1 million
tuple_ex =(tuple_ex[::-2])
aprint("Time take to retrieve every 2nd element from a tuple = ", tm.time()-tt)
Time take to retrieve every 2nd element from a list = 0.03334379196166992
Time take to retrieve every 2nd element from a tuple = 0.018698692321777344
= 2, 7, 4 tuple_example
We can check the data type of a python object using the type() function. Let us check the data type of the object tuple_example.
type(tuple_example)
tuple
Elements of a tuple can be extracted using their index within square brackets. For example the second element of the tuple tuple_example can be extracted as follows:
1] tuple_example[
7
Note that an element of a tuple cannot be modified. For example, consider the following attempt in changing the second element of the tuple tuple_example.
1] = 8 tuple_example[
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[49], line 1 ----> 1 tuple_example[1] = 8 TypeError: 'tuple' object does not support item assignment
The above code results in an error as tuple elements cannot be modified.
Now that we have an idea about tuple, let us try to think where it can be used.
6.2.7 Tuple Comprehension?
There is no direct tuple comprehension in Python. However, Python does allow a similar construct that looks like tuple comprehension but actually creates a generator expression. If you want to create a tuple using comprehension-like syntax, you can explicitly convert the generator to a tuple.
= (x**2 for x in range(5))
gen print(gen)
Here, gen
is a generator, not a tuple. Generators are lazily evaluated, meaning values are computed on demand, making them memory-efficient.
To create a tuple, we can use the tuple()
function to convert the generator into a tuple explicitly.
= tuple(x**2 for x in range(5))
tup print(tup) # Output: (0, 1, 4, 9, 16)
Why No Direct Tuple Comprehension?
- Python uses parentheses for both tuple creation and generator expressions. To avoid ambiguity, Python reserves parentheses for generators in this context.
- Converting a generator to a tuple ensures explicit behavior and consistency.
Using List Comprehension for a List of Tuples:
In Python, list comprehension is often used to create a list of tuples because it combines the flexibility of tuple creation with the concise syntax of list comprehension.
Example: Create a list of tuples, where each tuple consists of a natural number and its square, for natural numbers ranging from 5 to 15.
= [(x,x**2) for x in range(5,16)]
sqrt_natural_no_5_15 print(sqrt_natural_no_5_15)
6.2.8 Practice exercise 3
Below is a list consisting of responses to the question: “At what age do you think you will marry?” from students of the STAT303-1 Fall 2022 class.
=['24','30','28','29','30','27','26','28','30+','26','28','30','30','30','probably never','30','25','25','30','28','30+ ','30','25','28','28','25','25','27','28','30','30','35','26','28','27','27','30','25','30','26','32','27','26','27','26','28','37','28','28','28','35','28','27','28','26','28','26','30','27','30','28','25','26','28','35','29','27','27','30','24','25','29','27','33','30','30','25','26','30','32','26','30','30','I wont','25','27','27','25','27','27','32','26','25','never','28','33','28','35','25','30','29','30','31','28','28','30','40','30','28','30','27','by 30','28','27','28','30-35','35','30','30','never','30','35','28','31','30','27','33','32','27','27','26','N/A','25','26','29','28','34','26','24','28','30','120','25','33','27','28','32','30','26','30','30','28','27','27','27','27','27','27','28','30','30','30','28','30','28','30','30','28','28','30','27','30','28','25','never','69','28','28','33','30','28','28','26','30','26','27','30','25','Never','27','27','25'] exp_marriage_age
Use list comprehension to:
6.2.8.1
Remove the elements that are not integers - such as ‘probably never’, ‘30+’, etc. What is the length of the new list?
Hint: The built-in python function of the str
class - isdigit() may be useful to check if the string contains only digits.
6.2.8.2
Cap the values greater than 80 to 80, in the clean list obtained in (1). What is the mean age when people expect to marry in the new list?
6.2.8.3
Determine the percentage of people who expect to marry at an age of 30 or more.
6.2.9 Practice exercise 4
USA’s GDP per capita from 1960 to 2021 is given by the tuple T in the code cell below. The values are arranged in ascending order of the year, i.e., the first value is for 1960, the second value is for 1961, and so on. Print the years in which the GDP per capita of the US increased by more than 10%.
= (3007, 3067, 3244, 3375,3574, 3828, 4146, 4336, 4696, 5032,5234,5609,6094,6726,7226,7801,8592,9453,10565,11674,12575,13976,14434,15544,17121,18237,19071,20039,21417,22857,23889,24342,25419,26387,27695,28691,29968,31459,32854,34515,36330,37134,37998,39490,41725,44123,46302,48050,48570,47195,48651,50066,51784,53291,55124,56763,57867,59915,62805,65095,63028,69288) T
Determine the average GDP per capita for the given period (1960–2021).
Identify the year with the highest GDP per capita.
Identify the year with the lowest GDP per capita.
Create a new tuple where each element represents the percentage change in GDP per capita compared to the previous year.
Identify the year with the highest percentage increase in GDP per capita.
Construct a tuple where each element is a pair in the format (year, GDP per capita), making it easier to analyze trends over time.
Now that we have learned about lists and tuples, let us compare them.
\(\color{red}{\text{Q2}}\): A list seems to be much more flexible than tuple, and can replace a tuple almost everywhere. Then why use tuple at all?
\(\color{blue}{\text{A2}}\): The additional flexibility of a list comes at the cost of efficiency. Some of the advatages of a tuple over a list are as follows:
Since a list can be extended, space is over-allocated when creating a list. A tuple takes less storage space as compared to a list of the same length.
Tuples are not copied. If a tuple is assigned to another tuple, both tuples point to the same memory location. However, if a list is assigned to another list, a new list is created consuming the same memory space as the orignial list.
Tuples refer to their element directly, while in a list, there is an extra layer of pointers that refers to their elements. Thus it is faster to retrieve elements from a tuple.
The examples below illustrate the above advantages of a tuple.
#Example showing tuples take less storage space than lists for the same elements
= (1, 2, 'Obama')
tuple_ex = [1, 2, 'Obama']
list_ex print("Space taken by tuple =",tuple_ex.__sizeof__()," bytes")
print("Space taken by list =",list_ex.__sizeof__()," bytes")
#Examples showing that a tuples are not copied, while lists can be copied
= tuple(tuple_ex)
tuple_copy print("Is tuple_copy same as tuple_ex?", tuple_ex is tuple_copy)
= list(list_ex)
list_copy print("Is list_copy same as list_ex?",list_ex is list_copy)
#Examples showing tuples takes lesser time to retrieve elements
import time as tm
= tm.time()
tt = list(range(1000000)) #List containinig whole numbers upto 1 million
list_ex =(list_ex[::-2])
aprint("Time take to retrieve every 2nd element from a list = ", tm.time()-tt)
= tm.time()
tt = tuple(range(1000000)) #tuple containinig whole numbers upto 1 million
tuple_ex =(tuple_ex[::-2])
aprint("Time take to retrieve every 2nd element from a tuple = ", tm.time()-tt)
6.3 Sets
A set is a built-in data type in Python used to store unordered, unique, and mutable items. Sets are commonly used for operations like
- Membership testing: Quickly check if an item is in a set.
- Eliminating duplicate entries: Sets automatically ensure only unique elements are stored.
- Mathematical set operations: Supports union (
|
), intersection (&
), and difference (-
).
6.3.1 Creating a set
A set can be created using curly braces or the set()
constructor
= {1, 2, 3, 4}
my_set print(my_set)
= set([1, 2, 2, 3, 4])
my_set print(my_set)
type(my_set)
=set()
my_empty_setprint(my_empty_set)
A set can be also created by removing repeated elements from lists.
= [1,4,4,4,5,1,2,1,3]
my_list = list(set(my_list))
my_set_from_list print(my_set_from_list)
6.3.2 Accessing Elements
Since sets are unordered, you cannot use indexing or slicing:
= {"apple", "banana", "cherry"}
my_set 0] my_set[
Instead, you typically check membership or iterate over all elements:
if "apple" in my_set:
print("Apple is in the set")
for item in my_set:
print(item)
6.3.3 Adding and Removing Items
add(item)
: Adds an item to the set (if it’s not already present).update(iterable)
: Adds multiple items (from another set, list, tuple, etc.).remove(item)
: Removes the specified item (raises an error if not found).discard(item)
: Removes the specified item (does not raise an error if not found).clear()
: Removes all items.
# Add an element to a set
print(my_set)
5)
my_set.add(print(my_set)
# Remove an element from a set
3)
my_set.remove(print(my_set)
# Remove an element that doesn't exist
3) # This will raise a KeyError
my_set.remove(
# Remove an element that doesn't exist without raising an error
3) my_set.discard(
Remove an element using remove()
(raises an error if the element does not exist); Use discard()
to remove an element (does not raise an error if the element does not exist):
pop()
: Removes and returns an arbitrary item from the set.
in CPython, the commonly used Python implementation, it often returns the element with the lowest hash value, which for integers looks like the lowest number.
= {5, 2, 3, 1, 4}
s print("Original set:", s)
while s:
print("Popped:", s.pop(), "| Remaining:", s)
You might observe it pops values in ascending order (1, 2, 3…), but remember: this is not guaranteed in every Python version or implementation.
6.3.4 Mathematical Set Operations
Sets are ideal for tasks involving unions, intersections, and differences. The table below explains these operatoins on sets
Operation | Symbol | Method | Description |
---|---|---|---|
Union | | |
set_a.union(set_b) |
Combines all unique elements from two sets. |
Intersection | & |
set_a.intersection(set_b) |
Finds common elements between two sets. |
Difference | - |
set_a.difference(set_b) |
Finds elements in set_a but not in set_b . |
Symmetric Difference | ^ |
set_a.symmetric_difference(set_b) |
Finds elements in either set, but not both. |
# Examples of Mathematical Operations on Sets
= {1, 2, 3}
set_a = {3, 4, 5}
set_b
# Union
print(set_a | set_b)
# Intersection
print(set_a & set_b)
# Difference
print(set_a - set_b)
# Symmetric Difference
print(set_a ^ set_b)
6.3.5 Set Comprehension
We can do set comprehensions just like list comprehensions
# set comprehension
= {x for x in 'hello'}
my_set print(my_set)
type(my_set)
6.3.6 Practice exercise 5
The GDP per capita of USA for most years from 1960 to 2021 is given by the tuple D_tuple
given in the code cell below.
= ((1960, 3007), (1961, 3067), (1962, 3244), (1963, 3375), (1964, 3574), (1965, 3828),
D_tuple 1966, 4146), (1967, 4336), (1968, 4696), (1970, 5234), (1971, 5609), (1972, 6094),
(1973, 6726), (1974, 7226), (1975, 7801), (1976, 8592), (1978, 10565), (1979, 11674),
(1980, 12575), (1981, 13976), (1982, 14434), (1983, 15544), (1984, 17121), (1985, 18237),
(1986, 19071), (1987, 20039), (1988, 21417), (1989, 22857), (1990, 23889), (1991, 24342),
(1992, 25419), (1993, 26387), (1994, 27695), (1995, 28691), (1996, 29968), (1997, 31459),
(1998, 32854), (2000, 36330), (2001, 37134), (2002, 37998), (2003, 39490), (2004, 41725),
(2005, 44123), (2006, 46302), (2007, 48050), (2008, 48570), (2009, 47195), (2010, 48651),
(2011, 50066), (2012, 51784), (2013, 53291), (2015, 56763), (2016, 57867), (2017, 59915),
(2018, 62805), (2019, 65095), (2020, 63028), (2021, 69288)) (
Determine which years between 1960 and 2021 are missing GDP per capita data.
6.4 Dictionary
A Dictionary in Python is an mutable collection of key-value pairs. It’s used when you need to associate a specific value with a key and quickly access that value by using the key.
A dictionary in Python consists of key-value pairs, where both keys and values are Python objects. While values can be of any data type, keys must be immutable objects, such as strings, integers, or tuples. For example, a list can be used as a value in a dictionary, but not as a key, because lists are mutable and their elements can be changed.
Ordered Dictionaries: As of Python 3.7, the language specification guarantees that dictionaries maintain insertion order. This means you can reliably depend on the order in which keys were inserted when iterating over or converting the dictionary. Prior to Python 3.7, this behavior was not officially guaranteed (though in CPython 3.6, it happened to work that way in practice).
6.4.1 Creating a dictionary
Use braces {}
or the dict()
constructor.
# Using braces
= {
person "name": "Alice",
"age": 30,
"city": "New York"
}print(person)
# Using dict() constructor
= dict(brand="Tesla", model="Model 3", year=2023)
car print(car)
# Empty dictionary
= {}
empty_dict print(empty_dict)
6.4.2 Accessing and Modifying Values
Access values by their keys using square bracket notation [key]
or the .get(key)
method.
= {"name": "Alice", "age": 30, "city": "New York"}
person
# Access value
print(person["name"])
print(person.get("name"))
# Modify value
"age"] = 31
person[print(person)
# Add new key-value pair
"job"] = "Engineer"
person[print(person)
6.4.3 Removing Keys
pop(key)
: Removes and returns the value for key.del dictionary[key]
: Removes the key-value pair.popitem()
: Removes and returns an arbitrary key-value pair (in Python 3.7+, it removes the last inserted item).clear()
: Removes all items.
= {"name": "Alice", "age": 30, "city": "New York"}
person
= person.pop("age")
age print(age) # 30
print(person) # {"name": "Alice", "city": "New York"}
del person["name"]
print(person) # {"city": "New York"}
person.popitem()print(person) # {} (now empty)
person.clear()print(person) # {}
6.4.4 Iterating over elements of a dictionary
Use the following dictionary methods to retrieve all key and values at once:
keys()
: Returns the list of all keys present in the dictionary.values()
: Returns the list of all values present in the dictionaryitems()
: Returns all the items present in the dictionary. Each item will be inside a tuple as a key-value pair.
= {"apple": 3, "banana": 5, "cherry": 2}
fruits print(fruits.keys())
print(fruits.values())
for key,value in fruits.items():
print("The Head of State of",key,"is",value)
6.4.5 Practice exercise 6
The GDP per capita of USA for most years from 1960 to 2021 is given by the dictionary D
given in the code cell below.
Find:
- The GDP per capita in 2015
- The GDP per capita of 2014 is missing. Update the dictionary to include the GDP per capita of 2014 as the average of the GDP per capita of 2013 and 2015.
- Impute the GDP per capita of other missing years in the same manner as in (2), i.e., as the average GDP per capita of the previous year and the next year. Note that the GDP per capita is not missing for any two consecutive years.
- Print the years and the imputed GDP per capita for the years having a missing value of GDP per capita in (3).
= {'1960':3007,'1961':3067,'1962':3244,'1963':3375,'1964':3574,'1965':3828,'1966':4146,'1967':4336,'1968':4696,'1970':5234,'1971':5609,'1972':6094,'1973':6726,'1974':7226,'1975':7801,'1976':8592,'1978':10565,'1979':11674, '1980':12575,'1981':13976,'1982':14434,'1983':15544,'1984':17121,'1985':18237, '1986':19071,'1987':20039,'1988':21417,'1989':22857,'1990':23889,'1991':24342, '1992':25419,'1993':26387,'1994':27695,'1995':28691,'1996':29968,'1997':31459, '1998':32854,'2000':36330,'2001':37134,'2002':37998,'2003':39490,'2004':41725, '2005':44123,'2006':46302,'2007':48050,'2008':48570,'2009':47195,'2010':48651, '2011':50066,'2012':51784,'2013':53291,'2015':56763,'2016':57867,'2017':59915,'2018':62805, '2019':65095,'2020':63028,'2021':69288} D
6.4.6 Practice exercise 7
The code cell below defines an object having the nutrition information of drinks in starbucks. Assume that the manner in which the information is structured is consistent throughout the object.
={'Cool Lime Starbucks Refreshers™ Beverage': [{'Nutrition_type': 'Calories', 'value': 45}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 11}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Strawberry Acai Starbucks Refreshers™ Beverage': [{'Nutrition_type': 'Calories', 'value': 80}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 18}, {'Nutrition_type': 'Fiber', 'value': 1}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Very Berry Hibiscus Starbucks Refreshers™ Beverage': [{'Nutrition_type': 'Calories', 'value': 60}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 14}, {'Nutrition_type': 'Fiber', 'value': 1}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Evolution Fresh™ Organic Ginger Limeade': [{'Nutrition_type': 'Calories', 'value': 110}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 28}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 5}], 'Iced Coffee': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 5}], 'Iced Espresso Classics - Vanilla Latte': [{'Nutrition_type': 'Calories', 'value': 130}, {'Nutrition_type': 'Fat', 'value': 2.5}, {'Nutrition_type': 'Carb', 'value': 21}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 5}, {'Nutrition_type': 'Sodium', 'value': 65}], 'Iced Espresso Classics - Caffe Mocha': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 2.5}, {'Nutrition_type': 'Carb', 'value': 23}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 5}, {'Nutrition_type': 'Sodium', 'value': 90}], 'Iced Espresso Classics - Caramel Macchiato': [{'Nutrition_type': 'Calories', 'value': 130}, {'Nutrition_type': 'Fat', 'value': 2.5}, {'Nutrition_type': 'Carb', 'value': 21}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 5}, {'Nutrition_type': 'Sodium', 'value': 65}], 'Shaken Sweet Tea': [{'Nutrition_type': 'Calories', 'value': 80}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 19}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Berry Blossom White': [{'Nutrition_type': 'Calories', 'value': 60}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 15}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Black Mango': [{'Nutrition_type': 'Calories', 'value': 150}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 38}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 15}], 'Tazo® Bottled Black with Lemon': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 35}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Brambleberry': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 35}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 15}], 'Tazo® Bottled Giant Peach': [{'Nutrition_type': 'Calories', 'value': 150}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 37}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 15}], 'Tazo® Bottled Iced Passion': [{'Nutrition_type': 'Calories', 'value': 70}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 17}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Lemon Ginger': [{'Nutrition_type': 'Calories', 'value': 120}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 31}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Organic Black Lemonade': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 35}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Organic Iced Black Tea': [{'Nutrition_type': 'Calories', 'value': 60}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 15}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Organic Iced Green Tea': [{'Nutrition_type': 'Calories', 'value': 120}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 31}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Plum Pomegranate': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 35}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Tazo® Bottled Tazoberry': [{'Nutrition_type': 'Calories', 'value': 150}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 38}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 15}], 'Tazo® Bottled White Cranberry': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 35}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Teavana® Shaken Iced Black Tea': [{'Nutrition_type': 'Calories', 'value': 30}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 8}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 5}], 'Teavana® Shaken Iced Black Tea Lemonade': [{'Nutrition_type': 'Calories', 'value': 70}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 17}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Teavana® Shaken Iced Green Tea': [{'Nutrition_type': 'Calories', 'value': 30}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 8}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 5}], 'Teavana® Shaken Iced Green Tea Lemonade': [{'Nutrition_type': 'Calories', 'value': 70}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 17}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 5}], 'Teavana® Shaken Iced Passion Tango™ Tea': [{'Nutrition_type': 'Calories', 'value': 30}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 8}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 5}], 'Teavana® Shaken Iced Passion Tango™ Tea Lemonade': [{'Nutrition_type': 'Calories', 'value': 90}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 24}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Teavana® Shaken Iced Peach Green Tea': [{'Nutrition_type': 'Calories', 'value': 60}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 15}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Starbucks Refreshers™ Raspberry Pomegranate': [{'Nutrition_type': 'Calories', 'value': 90}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 27}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Starbucks Refreshers™ Strawberry Lemonade': [{'Nutrition_type': 'Calories', 'value': 90}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 27}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Starbucks® Doubleshot Protein Dark Chocolate': [{'Nutrition_type': 'Calories', 'value': 210}, {'Nutrition_type': 'Fat', 'value': 2.5}, {'Nutrition_type': 'Carb', 'value': 33}, {'Nutrition_type': 'Fiber', 'value': 2}, {'Nutrition_type': 'Protein', 'value': 20}, {'Nutrition_type': 'Sodium', 'value': 115}], 'Starbucks® Doubleshot Protein Vanilla': [{'Nutrition_type': 'Calories', 'value': 200}, {'Nutrition_type': 'Fat', 'value': 2.5}, {'Nutrition_type': 'Carb', 'value': 34}, {'Nutrition_type': 'Fiber', 'value': 2}, {'Nutrition_type': 'Protein', 'value': 20}, {'Nutrition_type': 'Sodium', 'value': 120}], 'Starbucks® Iced Coffee Caramel': [{'Nutrition_type': 'Calories', 'value': 60}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 13}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Starbucks® Iced Coffee Light Sweetened': [{'Nutrition_type': 'Calories', 'value': 50}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 11}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Starbucks® Iced Coffee Unsweetened': [{'Nutrition_type': 'Calories', 'value': 10}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 2}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Blonde Roast': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Clover® Brewed Coffee': [{'Nutrition_type': 'Calories', 'value': 10}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Decaf Pike Place® Roast': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Featured Dark Roast': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Nariño 70 Cold Brew': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 15}], 'Nariño 70 Cold Brew with Milk': [{'Nutrition_type': 'Calories', 'value': 0}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Nitro Cold Brew': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 0}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Nitro Cold Brew with Sweet Cream': [{'Nutrition_type': 'Calories', 'value': 70}, {'Nutrition_type': 'Fat', 'value': 5.0}, {'Nutrition_type': 'Carb', 'value': 5}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 20}], 'Pike Place® Roast': [{'Nutrition_type': 'Calories', 'value': 5}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 0}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 10}], 'Vanilla Sweet Cream Cold Brew': [{'Nutrition_type': 'Calories', 'value': 110}, {'Nutrition_type': 'Fat', 'value': 6.0}, {'Nutrition_type': 'Carb', 'value': 14}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 1}, {'Nutrition_type': 'Sodium', 'value': 25}], 'Hot Chocolate': [{'Nutrition_type': 'Calories', 'value': 320}, {'Nutrition_type': 'Fat', 'value': 9.0}, {'Nutrition_type': 'Carb', 'value': 47}, {'Nutrition_type': 'Fiber', 'value': 4}, {'Nutrition_type': 'Protein', 'value': 14}, {'Nutrition_type': 'Sodium', 'value': 160}], 'Starbucks® Signature Hot Chocolate': [{'Nutrition_type': 'Calories', 'value': 430}, {'Nutrition_type': 'Fat', 'value': 26.0}, {'Nutrition_type': 'Carb', 'value': 45}, {'Nutrition_type': 'Fiber', 'value': 5}, {'Nutrition_type': 'Protein', 'value': 12}, {'Nutrition_type': 'Sodium', 'value': 115}], 'Caffè Latte': [{'Nutrition_type': 'Calories', 'value': 190}, {'Nutrition_type': 'Fat', 'value': 7.0}, {'Nutrition_type': 'Carb', 'value': 19}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 13}, {'Nutrition_type': 'Sodium', 'value': 170}], 'Caffè Mocha': [{'Nutrition_type': 'Calories', 'value': 290}, {'Nutrition_type': 'Fat', 'value': 8.0}, {'Nutrition_type': 'Carb', 'value': 42}, {'Nutrition_type': 'Fiber', 'value': 4}, {'Nutrition_type': 'Protein', 'value': 13}, {'Nutrition_type': 'Sodium', 'value': 140}], 'Cappuccino': [{'Nutrition_type': 'Calories', 'value': 120}, {'Nutrition_type': 'Fat', 'value': 4.0}, {'Nutrition_type': 'Carb', 'value': 12}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 8}, {'Nutrition_type': 'Sodium', 'value': 100}], 'Caramel Macchiato': [{'Nutrition_type': 'Calories', 'value': 250}, {'Nutrition_type': 'Fat', 'value': 7.0}, {'Nutrition_type': 'Carb', 'value': 35}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 10}, {'Nutrition_type': 'Sodium', 'value': 150}], 'Cinnamon Dolce Latte': [{'Nutrition_type': 'Calories', 'value': 260}, {'Nutrition_type': 'Fat', 'value': 6.0}, {'Nutrition_type': 'Carb', 'value': 40}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 11}, {'Nutrition_type': 'Sodium', 'value': 150}], 'Coconutmilk Mocha Macchiato': [{'Nutrition_type': 'Calories', 'value': 250}, {'Nutrition_type': 'Fat', 'value': 9.0}, {'Nutrition_type': 'Carb', 'value': 32}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 12}, {'Nutrition_type': 'Sodium', 'value': 180}], 'Flat White': [{'Nutrition_type': 'Calories', 'value': 180}, {'Nutrition_type': 'Fat', 'value': 7.0}, {'Nutrition_type': 'Carb', 'value': 18}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 12}, {'Nutrition_type': 'Sodium', 'value': 160}], 'Iced Caffè Latte': [{'Nutrition_type': 'Calories', 'value': 130}, {'Nutrition_type': 'Fat', 'value': 4.5}, {'Nutrition_type': 'Carb', 'value': 13}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 8}, {'Nutrition_type': 'Sodium', 'value': 115}], 'Iced Caffè Mocha': [{'Nutrition_type': 'Calories', 'value': 230}, {'Nutrition_type': 'Fat', 'value': 6.0}, {'Nutrition_type': 'Carb', 'value': 36}, {'Nutrition_type': 'Fiber', 'value': 4}, {'Nutrition_type': 'Protein', 'value': 9}, {'Nutrition_type': 'Sodium', 'value': 90}], 'Iced Caramel Macchiato': [{'Nutrition_type': 'Calories', 'value': 250}, {'Nutrition_type': 'Fat', 'value': 7.0}, {'Nutrition_type': 'Carb', 'value': 37}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 10}, {'Nutrition_type': 'Sodium', 'value': 150}], 'Iced Cinnamon Dolce Latte': [{'Nutrition_type': 'Calories', 'value': 200}, {'Nutrition_type': 'Fat', 'value': 4.0}, {'Nutrition_type': 'Carb', 'value': 34}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 7}, {'Nutrition_type': 'Sodium', 'value': 95}], 'Iced Coconutmilk Mocha Macchiato': [{'Nutrition_type': 'Calories', 'value': 260}, {'Nutrition_type': 'Fat', 'value': 9.0}, {'Nutrition_type': 'Carb', 'value': 34}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 11}, {'Nutrition_type': 'Sodium', 'value': 180}], 'Iced Vanilla Latte': [{'Nutrition_type': 'Calories', 'value': 190}, {'Nutrition_type': 'Fat', 'value': 4.0}, {'Nutrition_type': 'Carb', 'value': 30}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 7}, {'Nutrition_type': 'Sodium', 'value': 100}], 'Iced White Chocolate Mocha': [{'Nutrition_type': 'Calories', 'value': 300}, {'Nutrition_type': 'Fat', 'value': 8.0}, {'Nutrition_type': 'Carb', 'value': 47}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 10}, {'Nutrition_type': 'Sodium', 'value': 190}], 'Latte Macchiato': [{'Nutrition_type': 'Calories', 'value': 190}, {'Nutrition_type': 'Fat', 'value': 7.0}, {'Nutrition_type': 'Carb', 'value': 19}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 12}, {'Nutrition_type': 'Sodium', 'value': 160}], 'Starbucks Doubleshot® on Ice Beverage': [{'Nutrition_type': 'Calories', 'value': 45}, {'Nutrition_type': 'Fat', 'value': 1.0}, {'Nutrition_type': 'Carb', 'value': 5}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 3}, {'Nutrition_type': 'Sodium', 'value': 40}], 'Vanilla Latte': [{'Nutrition_type': 'Calories', 'value': 250}, {'Nutrition_type': 'Fat', 'value': 6.0}, {'Nutrition_type': 'Carb', 'value': 37}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 12}, {'Nutrition_type': 'Sodium', 'value': 150}], 'White Chocolate Mocha': [{'Nutrition_type': 'Calories', 'value': 360}, {'Nutrition_type': 'Fat', 'value': 11.0}, {'Nutrition_type': 'Carb', 'value': 53}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 14}, {'Nutrition_type': 'Sodium', 'value': 240}], 'Cinnamon Dolce Frappuccino® Blended Coffee': [{'Nutrition_type': 'Calories', 'value': 350}, {'Nutrition_type': 'Fat', 'value': 4.5}, {'Nutrition_type': 'Carb', 'value': 64}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 15}, {'Nutrition_type': 'Sodium', 'value': 0}], 'Coffee Light Frappuccino® Blended Coffee': [{'Nutrition_type': 'Calories', 'value': 110}, {'Nutrition_type': 'Fat', 'value': 0.0}, {'Nutrition_type': 'Carb', 'value': 24}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 3}, {'Nutrition_type': 'Sodium', 'value': 200}], 'Mocha Frappuccino® Blended Coffee': [{'Nutrition_type': 'Calories', 'value': 280}, {'Nutrition_type': 'Fat', 'value': 2.5}, {'Nutrition_type': 'Carb', 'value': 60}, {'Nutrition_type': 'Fiber', 'value': 2}, {'Nutrition_type': 'Protein', 'value': 4}, {'Nutrition_type': 'Sodium', 'value': 220}], 'Mocha Light Frappuccino® Blended Coffee': [{'Nutrition_type': 'Calories', 'value': 140}, {'Nutrition_type': 'Fat', 'value': 0.5}, {'Nutrition_type': 'Carb', 'value': 28}, {'Nutrition_type': 'Fiber', 'value': 1}, {'Nutrition_type': 'Protein', 'value': 4}, {'Nutrition_type': 'Sodium', 'value': 180}], 'Cinnamon Dolce Crème': [{'Nutrition_type': 'Calories', 'value': 200}, {'Nutrition_type': 'Fat', 'value': 6.0}, {'Nutrition_type': 'Carb', 'value': 28}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 10}, {'Nutrition_type': 'Sodium', 'value': 135}], 'Vanilla Crème': [{'Nutrition_type': 'Calories', 'value': 200}, {'Nutrition_type': 'Fat', 'value': 6.0}, {'Nutrition_type': 'Carb', 'value': 28}, {'Nutrition_type': 'Fiber', 'value': 0}, {'Nutrition_type': 'Protein', 'value': 10}, {'Nutrition_type': 'Sodium', 'value': 135}], 'Chocolate Smoothie': [{'Nutrition_type': 'Calories', 'value': 320}, {'Nutrition_type': 'Fat', 'value': 5.0}, {'Nutrition_type': 'Carb', 'value': 53}, {'Nutrition_type': 'Fiber', 'value': 8}, {'Nutrition_type': 'Protein', 'value': 20}, {'Nutrition_type': 'Sodium', 'value': 170}], 'Strawberry Smoothie': [{'Nutrition_type': 'Calories', 'value': 300}, {'Nutrition_type': 'Fat', 'value': 2.0}, {'Nutrition_type': 'Carb', 'value': 60}, {'Nutrition_type': 'Fiber', 'value': 7}, {'Nutrition_type': 'Protein', 'value': 16}, {'Nutrition_type': 'Sodium', 'value': 130}]} starbucks_drinks_nutrition
Use the object above to answer the following questions:
6.4.6.1
What is the datatype of the object?
6.4.6.2
If the object in (1) is a dictionary, what is the datatype of the values of the dictionary?
6.4.6.3
If the object in (1) is a dictionary, what is the datatype of the elements within the values of the dictionary?
6.4.6.4
How many calories are there in Iced Coffee
?
6.4.6.5
Which drink(s) have the highest amount of protein in them, and what is that protein amount?
6.4.6.6
Which drink(s) have a fat content of more than 10g, and what is their fat content?
6.5 Choosing the Right Data Structure
- List
- Ordered and Mutable
- Best for collections of related items you need to modify, iterate, or reorder frequently.
- Ordered and Mutable
- Tuple
- Ordered and Immutable
- Ideal for data that shouldn’t change or for use as dictionary keys (since they are hashable).
- Ordered and Immutable
- Dictionary
- Unordered (maintains insertion order in Python 3.7+) and Mutable
- Perfect for key-value lookups, fast data retrieval based on unique keys, and clearly organizing named data.
- Unordered (maintains insertion order in Python 3.7+) and Mutable
- Set
- Unordered and Mutable
- Automatically enforces unique elements. Great for membership testing (e.g.,
in
checks) and set operations like union, intersection, etc.
- Unordered and Mutable
6.6 Immutable and mutable Data Types in Python
In Python, immutable data types are those whose values cannot be changed after they are created. If you try to modify an immutable object, Python will create a new object instead of changing the original one.
Here is a list of immutable data types in python
- Integers (
int
) - Floats (
float
) - Booleans (
bool
) - Strings (
str
) - Tuples (
tuple
)
Key Characteristics of Immutable Data Types
Cannot be modified in place: Any operation that appears to modify an immutable object actually creates a new object.
Hashable: Immutable objects can be used as keys in dictionaries or elements in sets because their values do not change.
Memory Efficiency: Python may reuse memory for immutable objects (e.g., small integers or short strings) to optimize performance.
# when you try to modify the interger, it creates a new integer object
= 32
my_integer
# Memory address of my_integer
print("Memory address of my_integers:", id(my_integer))
= 12
my_integer # Memory address of my_integer
print("Memory address of my_integers:", id(my_integer))
= "hello"
s
0] = 'H' s[
# Immutable example: Strings
= "hello"
s
print("Original string:", s)
print("Memory address of original s:", id(s))
= s.upper()
s print("New string:", s.upper())
print("Memory address of s.upper:", id(s.upper))
For comparison, here are some mutable data types in Python:
- Lists (
list
) - Dictionaries (
dict
) - Sets (
set
)
# Mutable example: Lists
= [1, 2, 3]
lst print("list before modification:", lst)
print("Memory address of lst:", id(lst))
# Modifying the list
4)
lst.append(print("list after modification:", lst)
print("Memory address of lst:", id(lst))
6.7 Final Thoughts
- Lists are your go-to when you need an adjustable sequence of ordered items.
- Tuples provide a way to store data in an immutable sequence, ensuring it remains unchanged.
- Dictionaries let you organize data into key-value pairs for quick lookups and clearer data structures.
- Sets focus on uniqueness and membership operations, which can greatly optimize tasks like deduplication and intersection.
Choose the right data structure based on your needs to write concise, efficient, and easy-to-maintain code.
6.7.1 Bonus Practice exercise
The object deck
defined below corresponds to a deck of cards. Estimate the probablity that a five card hand will be a flush, as follows:
- Write a function that accepts a hand of 5 cards as argument, and returns whether the hand is a flush or not.
- Randomly pull a hand of 5 cards from the deck. Call the function developed in (1) to determine if the hand is a flush.
- Repeat (2) 10,000 times.
- Estimate the probability of the hand being a flush from the results of the 10,000 simulations.
You may use the function shuffle() from the random
library to shuffle the deck everytime before pulling a hand of 5 cards.
= [{'value':i, 'suit':c}
deck for c in ['spades', 'clubs', 'hearts', 'diamonds']
for i in range(2,15)]
Solution:
import random as rm
#Function to check if a 5-card hand is a flush
def chck_flush(hands):
#Assuming that the hand is a flush, before checking the cards
=1
yes_flush
#Storing the suit of the first card in 'first_suit'
= hands[0]['suit']
first_suit
#Iterating over the remaining 4 cards of the hand
for j in range(1,len(hands)):
#If the suit of any of the cards does not match the suit of the first card, the hand is not a flush
if first_suit!=hands[j]['suit']:
= 0;
yes_flush
#As soon as a card with a different suit is found, the hand is not a flush and there is no need to check other cards. So, we 'break' out of the loop
break;
return yes_flush
=0
flushfor i in range(10000):
#Shuffling the deck
rm.shuffle(deck)
#Picking out the first 5 cards of the deck as a hand and checking if they are a flush
#If the hand is a flush it is counted
=flush+chck_flush(deck[0:5])
flush
print("Probability of obtaining a flush=", 100*(flush/10000),"%")