Dictionaries

Recall how we were able to associate kids with their favourite thing about Halloween on the midterm: we used two parallel lists:

In [1]:
kids  = ["Bob",   "Dorothy",  "Alice"]
faves = ["candy", "costumes", "midterms"]

We said that the favourite of kids[i] is faves[i].

Dictionaries provide us with a better way to accomplish the same thing. Here is how things would work:

In [2]:
faves = {"Bob": "candy", "Dorothy": "costumes", "Alice": "midterms"}
In [3]:
faves["Alice"]
Out[3]:
'midterms'

"Bob", "Dorothy", and "Alice" are called keys. "candy", "costumes", and "midterms" are called values. We can access the value associted with the key k in a dictionary d using d[k]. That is what we do when we go faves["Alice"].

The dictionary faves is defined inside the curly braces, with keys and values separated by :, and with entries (i.e., key-value pairs) separated by commas.

Basic dictionary usage

Let's define a new dictionary, grades.

In [4]:
grades = {"PHY": 90, "CSC": 85, "CIV": 100, "ESC": 85}

We can modify existing values like this:

In [5]:
grades["CSC"] = 84
In [6]:
grades
Out[6]:
{'CIV': 100, 'CSC': 84, 'ESC': 85, 'PHY': 90}

We can also add entries, like this:

In [7]:
grades["MAT"] = 87 
In [8]:
grades
Out[8]:
{'CIV': 100, 'CSC': 84, 'ESC': 85, 'MAT': 87, 'PHY': 90}

Note that this is not similar to what can be done with lists: if an index does not exist in a list, we cannot add a value at that index:

In [9]:
L = [4, 5, 6]
L[100] = 10
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-9-6963b38d2b20> in <module>()
      1 L = [4, 5, 6]
----> 2 L[100] = 10

IndexError: list assignment index out of range

Using dictionaries to associate numbers to other numbers

Let's store the UofT endowment (in millions of dollars) in different years

In [10]:
endowment = {2012: 1518.2, 2014: 1881.7, 2015: 2142.5, 2016: 2097.1}

Note that we could use a list, but that would require us to also have endowment[0], endowment[1], etc.

Different types of values

Back to grades:

In [11]:
grades
Out[11]:
{'CIV': 100, 'CSC': 84, 'ESC': 85, 'MAT': 87, 'PHY': 90}

We don't have to have all the values (or all the keys) be the same type. For example, we can go

In [12]:
grades["CSC"] = {"MT": 50, "Exam": 100, "Proj": 95}
In [13]:
grades
Out[13]:
{'CIV': 100,
 'CSC': {'Exam': 100, 'MT': 50, 'Proj': 95},
 'ESC': 85,
 'MAT': 87,
 'PHY': 90}

Keys have to be immutable

Keys in a dictionary have to be immutable. The following doesn't work:

In [14]:
L = [1, 2]
grades[L] = 5
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-14-7d390bfc882d> in <module>()
      1 L = [1, 2]
----> 2 grades[L] = 5

TypeError: unhashable type: 'list'

Why not? Basically, it's unclear what should happen if we go L[0] = 15. Should grades[L] be the same, or hsould 5 always be grades[[1, 2]]? We could make the choice, in principle, but, for various reasons, Python simply doesn't allow for keys to be mutable.

Keys, values, and items

Here is how you can get the list of all the keys in a dictionary:

In [15]:
list(endowment.keys())
Out[15]:
[2016, 2012, 2014, 2015]

All the values:

In [16]:
list(endowment.values())
Out[16]:
[2097.1, 1518.2, 1881.7, 2142.5]

Note that the keys and the values are given in no particular order. We can go through all the keys, and all the values, using for-loops:

In [17]:
for year in endowment.keys():
    print(year)
2016
2012
2014
2015
In [18]:
for year in endowment: #get all the keys, in some order
    print(year) 
2016
2012
2014
2015
In [19]:
for amt in endowment.values():
    print(amt)
2097.1
1518.2
1881.7
2142.5

You can also get the items in a dictionary -- those are the key-value pairs, as tuples:

In [20]:
grades = {"CSC": 87, "CIV": 100, "MAT": 95, "ESC": 95}
list(grades.items())
Out[20]:
[('CIV', 100), ('MAT', 95), ('CSC', 87), ('ESC', 95)]

Iterating through a dictionary

We can iterate through the keys, as we saw above:

In [21]:
for subj in grades:
    print("I got", grades[subj], "in", subj)     
I got 100 in CIV
I got 95 in MAT
I got 87 in CSC
I got 95 in ESC

We can also iterate through the items:

In [22]:
for subj, grade in grades.items():
    print("I got", grade, "in", subj)   
I got 100 in CIV
I got 95 in MAT
I got 87 in CSC
I got 95 in ESC

Here, we unpacked each item into subj and grade.

Again, note that when using a for-loop, the keys/items are not guaranteed to come in any particular order.