6.2 — More list & set operations, Dictionaries

Updating multiple items in a list using slice assignment

The syntax of the slice assignment is as follows:

list_object[start:stop:step] = iterable

For now, think of iterable as a sequence/container such as a list, string, tuple etc.

1days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
2print(days[1:3])
3# ['Tue', 'Wed']
4
5days[1:3] = [1, 2]
6print(days)
7# ['Mon', 1, 2, 'Thu', 'Fri', 'Sat', 'Sun']

1days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
2print(days[1::2])
3# ['Tue', 'Thu', 'Sat']
4
5days[1::2] = ["", "", ""]
6print(days)
7# ['Mon', '', 'Wed', '', 'Fri', '', 'Sun']
8
9days[:3] = "MTW"
10print(days)
11# ['M', 'T', 'W', '', 'Fri', '', 'Sun']

Other list methods

1# list.reverse() : Reverse the list "in place"
2grades = [90, 70, 60.5, 70, 80]
3grades.reverse()
4print(grades) # [80, 70, 60.5, 70, 90]
5
6# list.clear() : Remove all items from list.
7grades = [90, 70, 60.5, 70, 80]
8grades.clear()
9print(grades) # []

What modifies a list?

  • Assigning a value to an element using its index.
    1a = [1, 2, 3]
    2a[0] = 5
  • Using the slice assignment to modify the elements of a list.
    1a = [1, 2, 3]
    2a[:2] = [4, 5]
  • Using methods like append(), insert(), remove() , pop(), clear(), etc.

What does not modify a list?

  • Slicing! It is a useful tool to create new lists out of an existing lists.
    1a = [1, 2, 3]
    2b = a[:] # makes a copy of a
    3print(a is b) # False
  • The + and * operators create a new list
    1a = [1, 2, 3]
    2b = a # does not copy, just a new name for same list
    3b = b + [4] # b now refers to a new list [1, 2, 3, 4]
    4 # a still refers to [1, 2, 3]
    5print(a is b) # False

Set methods

1# set.update(iterable):
2# Adds all items from the iterable to the set.
3
4numbers = {1, 2, 3}
5numbers.update([10, 2, 2, 3, 20])
6print(numbers) # {1, 2, 3, 10, 20}
7
8numbers.update(("a", "b"))
9print(numbers) # {1, 2, 3, 'a', 10, 20, 'b'}
10
11primes = {2, 3, 5}
12primes.update({5, 7, 11})
13print(primes) # {2, 3, 5, 7, 11}

1# set.clear(): Remove all elements from this set.
2
3numbers = {1, 2, 3}
4numbers.clear()
5print(numbers) # set()

1# For the following methods, suppose A and B are sets.
2
3# A.intersection(B):
4# Returns a new set that contains elements that are
5# present in both A and B
6
7odd = {3, 5, 7, 9, 25}
8squares = {4, 9, 25, 36}
9odd_squares = odd.intersection(squares)
10print(odd_squares) # {9, 25}
11
12# Intersection can also be done using operator &
13odd_squares = odd & squares
14print(odd_squares) # {9, 25}

1# A.union(B):
2# Returns a new set that contains elements that are
3# present in A or B or both
4
5x = {1, 2, 3}
6y = {2, 3, 5}
7all_numbers = x.union(y)
8print(all_numbers) # {1, 2, 3, 5}
9
10# Same above but using an operator |
11all_numbers = x | y
12print(all_numbers) # {1, 2, 3, 5}

1# A.difference(B):
2# Returns a new set that contains elements that are
3# present only in A but not in B
4x = {1, 2, 3}
5y = {2, 3, 5}
6diff = x.difference(y)
7print(diff) # {1}
8
9# Same as above but using operator -
10diff = x - y
11print(diff) # {1}

All of the set methods work the same when elements are of other types such as strings.

Dictionaries

Suppose we would like to store the following enrollment data:

semesterno. of students
F2017816
W2018613
F2018709
W2019590

We can do this using two lists for the two columns:

1semesters = ['F2017', 'W2018', 'F2018', 'W2019']
2students = [816, 613, 709, 590]

What should we do if we want to add new data?

1semesters = ['F2017', 'W2018', 'F2018', 'W2019']
2students = [816, 613, 709, 590]
3
4semesters.append("F2020")
5students.append(550)
6# ['F2017', 'W2018', 'F2018', 'W2019', 'F2020']
7# [816, 613, 709, 590, 550]

What if we want to modify the value for a specific semester?

1semesters = ['F2017', 'W2018', 'F2018', 'W2019']
2students = [816, 613, 709, 590]
3
4idx = semesters.index("W2018")
5students[idx] = 600

What we if try to add an entry for a semester that already exists?

List allows duplicates so it does not check if a semester already exists.

1semesters = ['F2017', 'W2018', 'F2018', 'W2019']
2students = [816, 613, 709, 590]
3
4semesters.append("F2018")
5students.append(500)
6# ['F2017', 'W2018', 'F2018', 'W2019', 'F2018']
7# [816, 613, 709, 590, 500]

Use a dictionary!

  • You can think of an item of a dictionary as a pair of objects:
    • The first object of the pair is called a key.
    • The second object is referred to as the value.
  • A dictionary is called a mapping type because it maps key objects to value objects.
1# A dictionary is created using a sequence of key-value pairs
2enrollment = {'F2017': 816, 'W2018': 613,
3 'F2018': 709, 'W2019': 590}
4
5print(type(enrollment)) # <class 'dict'>

1# Number of key-value pairs
2print(len(enrollment)) # 4
3
4# This is an empty dictionary, not a set!
5empty_dict = {}
6print(len(empty_dict)) # 0

Dictionary Examples

1# Key: a number, Value: True if number is prime, else False
2is_prime = {2: True, 3: True, 4: False, 5: True,
3 7: True, 10: False}
4
5# Key: inventory items, Value: count of items in inventory
6inventory = {"sofa": 5, "table": 10, "chair": 20, "mattress": 5}
7
8# Key: city name, Value: area of city
9population = {"Montreal": 431.50, "Toronto": 630.20}
10
11# Key: country name, Value: capital city
12capitals = {"Canada": "Ottawa", "United States": "Washington, D.C.",
13 "France": "Paris", "Germany": "Berlin"}

Note on keys and values

  • Keys
    • Have to be immutable objects.
    • Have to be unique in a dictionary. A dictionary cannot contain two items with the same key.
  • Values
    • Values can be of any type; both mutable and immutable values are allowed.
    • Many keys can map to the same value. i.e. values need not be unique.

Dictionary Lookup

With lists, we can access an item of the list through its index.

With dictionaries, we can access a value stored in the dictionary through the key associated with it.

1enrollment = {'F2017': 816, 'W2018': 613, 'F2018': 709,
2 'W2019': 590, 'F2019': 744}
3
4num_students = enrollment["F2018"]
5print(num_students) # 709
6
7# Key must exist in the dictionary if we want to access its value
8print(enrollment["F2020"]) # KeyError: 'F2020'

Adding an item

We can add a new item by specifying a key and a value: dictionary[key] = value

1enrollment = {'F2018': 709, 'W2019': 590}
2
3enrollment["F2020"] = 800 # add an item
4enrollment["W2020"] = 900 # add another item
5
6# {'F2018': 709, 'W2019': 590, 'F2020': 800, 'W2020': 900}
7
8enrollment["F2018"] = 700 # change an existing item
9
10# {'F2018': 700, 'W2019': 590, 'F2020': 800, 'W2020': 900}

Removing an item

We can delete an item using the following syntax: del dictionary[key]

1enrollment = {'F2018': 709, 'W2019': 590, 'F2019': 744}
2
3del enrollment["F2019"]
4
5# {'F2018': 709, 'W2019': 590}
6
7del enrollment["F2020"]
8# KeyError: 'F2020'

What will be printed in the following examples?

1d = {'x' : 0, 'y' : 1, 'z' : 2}
2x = d['y']
3print(x)
1d = {'x' : 0, 'y' : 1, 'z' : 2}
2x = d[0]
3print(x)

Check for membership

We can check if a key is part of a dictionary using the in and not in operators.

1d = {'x' : 0, 'y' : 1, 'z' : 2}
2print('x' in d) # True
3print(0 in d) # False
4print(0 not in d) # True

Iterating through a dictionary

We can use a for loop to iterate through all the keys in a dictionary.

1enrollment = {'F2018': 709, 'W2019': 590, 'F2019': 744}
2
3for key in enrollment:
4 print(key, "->", enrollment[key])
Output
F2018 -> 709
W2019 -> 590
F2019 -> 744

Functions and methods for dictionaries

1# dict(L): creates and returns a dictionary using a list L of tuples,
2# where each tuple is of length 2 in form of (key, value).
3
4pairs = [("Montreal", 1.78), ("Rome", 2.87), ("Tokyo", 9.27)]
5population_data = dict(pairs)
6
7print(population_data)
8# {'Montreal': 1.78, 'Rome': 2.87, 'Tokyo': 9.27}
9
10print(population_data["Rome"])
11# 2.87

1population_data = {'Montreal': 1.78, 'Rome': 2.87, 'Tokyo': 9.27}
2
3# dict.keys(): returns a iterable (sequence) of all keys
4
5cities = list(population_data.keys())
6print(cities) # ['Montreal', 'Rome', 'Tokyo']
7
8# dict.values(): returns a iterable (sequence) of all values
9
10population = list(population_data.values())
11print(population) # [1.78, 2.87, 9.27]

1# dict.items(): returns a iterable (sequence) of tuples (key, value)
2# for all items in the dictionary
3
4population_data = {'Montreal': 1.78, 'Rome': 2.87, 'Tokyo': 9.27}
5pairs = list(population_data.items())
6
7print(pairs)
8# [('Montreal', 1.78), ('Rome', 2.87), ('Tokyo', 9.27)]

For more methods, use help(dict).

Using the dict methods in for loop:

1population_data = {'Montreal': 1.78, 'Rome': 2.87, 'Tokyo': 9.27}
2
3total = 0
4for population in population_data.values():
5 total += population
6
7print(total) # 13.92

1population_data = {'Montreal': 1.78, 'Rome': 2.87, 'Tokyo': 9.27}
2
3# dict.items() returns an iterable of key-value tuples
4
5for tup in population_data.items():
6 city = tup[0]
7 population = tup[1]
8 print(city, "->", population)
9
10# Montreal -> 1.78
11# Rome -> 2.87
12# Tokyo -> 9.27

Making use of tuple unpacking in the for loop:

1population_data = {'Montreal': 1.78, 'Rome': 2.87, 'Tokyo': 9.27}
2
3for city, population in population_data.items():
4 print(city, "->", population)
5
6# Montreal -> 1.78
7# Rome -> 2.87
8# Tokyo -> 9.27

Time for some problems on Ed Lessons.