Dictionaries

Key-Value Pairs

The Dictionary Data Structure

We have seen several data structures so far. To name a few: * NumPy array: A sequence of elements, all of the same data type. Each element has an index, and we can access elements by their index using the item method or square-bracket indexing. We use the NumPy one-dimensional array in this course. * List: A sequence of elements, potentially of different data types. Each element has an index, and we can access elements by their index using square-bracket indexing. Python has a built-in list type. * Tables: A sequence of rows, where each row consists of values corresponding to a series of columns. Rows and columns are in sequence. We can access rows by their index using the take or row methods. We use the datascience package Table data type.

Arrays, lists, and tables have one core feature in common: their elements (or rows) are in order, and we can access these elements by index. But what if elements don’t naturally have an order? We must turn to different data structures; one such data structure is a dictionary.

In Python, a dictionary is a data structure that stores a set of key-value pairs.

dog = {
    'name': 'Junior',
    4: ['kibble', 'treat']
}
dog
{'name': 'Junior', 4: ['kibble', 'treat']}

The above syntax creates a dictionary called dog with two keys. Each key has an associated value:

  • key 'name': value 'Junior'
  • key 4: value ['kibble', 'treat'] (a list)

Basic Dictionary Use

Read/access dictionary. In order to retrieve an element from a dictionary, we use its key:

dog['name']
'Junior'

Attempting to get the value of a key that does not exist in the dictionary will throw an error:

dog['breed']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[3], line 1
----> 1 dog['breed']

KeyError: 'breed'

Write to a dictionary by providing a key and its associated value. Suppose we wanted to add the dog’s age to the dictionary:

dog['age'] = 11
dog
{'name': 'Junior', 4: ['kibble', 'treat'], 'age': 11}

Modify a dictionary by overwriting the value associated with a key. Note this works because dictionaries have unique keys:

dog['age'] = 12
dog
{'name': 'Junior', 4: ['kibble', 'treat'], 'age': 12}

Removing keys with pop

The key 4 does not describe its value well:

dog[4]
['kibble', 'treat']

Task: Renaming a key

Write two lines such that the dictionary dog will have the key 'likes' assigned to the list ['kibble', 'treat'] and will not have the key 4.

Note: To remove the existing key from dictionary dog, you can use dog.pop(key).

The below approach is succinct. The only thing that is changing is the key itself. Assign a new key to the existing value, then pop off the original key.

"""
Succinct solution
"""
dog['likes'] = dog[4]
dog.pop(4)
['kibble', 'treat']

Other approaches which aren’t incorrect per se, but have some data duplication and therefore will be quite tedious in practice:

"""
This solution reassigns the name to an entirely
new dictionary, requiring the programmer to manually rewrite
the entire dictionary
"""
dog = {
    'name': 'Junior',
    'likes': ['kibble', 'treat']
}
dog
{'name': 'Junior', 'likes': ['kibble', 'treat']}
"""
This solution first deletes the key-value, then
assignes the new key-value, requiring the programmer to
manually rewrite the original value (which hasn't changed)
"""

dog = { # the original dictionary, again
    'name': 'Junior',
    4: ['kibble', 'treat']
}
dog.pop(4) # delete the unneeded key
dog['likes'] = ['kibble', 'treat']
dog
{'name': 'Junior', 'likes': ['kibble', 'treat']}

Usage of pop: To pop key and avoid errors when the key doesn’t exist, you can provide a second argument None to pop:

dog.pop(4, None)

Why? Find out the answer in the official Python documentation on pop!

Dictionary Properties

Dictionary definitions/notes:

  • A key is what we use to look up values in a dictionary. This can be numbers or strings. Because we access values by keys, we suggest using “meaningful” keys, which are often strings.
  • A value can be anything—numbers, strings, lists, or even other dictionaries.
  • In a dictionary, each value has a key. Keys in a dictionary are unique.

Dictionary syntax:

  • `Curly brackets denote the start and end of a dictionary.
  • A colon is used to specify a single key-value pair; commas separate key-value pairs.

Conditions and Iterations with Dictionaries

Suppose we want to create a dictionary of slang:

slang = {
    'haha': 'that was not funny',
    'smh': 'shake my head',
    'lol': 'laugh out loud',
    'GOAT': 'greatest of all time'
}
slang
{'haha': 'that was not funny',
 'smh': 'shake my head',
 'lol': 'laugh out loud',
 'GOAT': 'greatest of all time'}
# Number of key-value pairs
len(slang)
4
# Checks if 'smh' is a key
'smh' in slang
True
# Checks if 'shake my head' is a key
# It is not – it is a value
'shake my head' in slang
False

Iterating over dictionaries with a for loop

Like many other data structures we have seen, we can use for loops to iterate over dictionaries. We discuss several approaches below: * Using the dictionary methods keys, values, and items * Using the dictionary name itself

We can iterate over the keys of a dictionary using the keys dictionary method:

for abb in slang.keys():
    print(abb, slang[abb])
haha that was not funny
smh shake my head
lol laugh out loud
GOAT greatest of all time

Python also allows us to provide the dictionary itself as the data structure to be iterated over, without any method calls. By doing so (as below), the iterated elements are the keys itself. The below code has the same behavior as the previous code:

for abb in slang:
    print(abb, slang[abb])
haha that was not funny
smh shake my head
lol laugh out loud
GOAT greatest of all time

Occasionally, you may want to iterate over just the values in a dictionary, without knowing the keys. This is rare:

for slang_phrase in slang.values():
    print(slang_phrase)
that was not funny
shake my head
laugh out loud
greatest of all time

In Python, the below structure is probably the most common. items returns Python tuples of (key, value), which we respectively assign to k and v:

for k, v in slang.items():
    print(k, v)
haha that was not funny
smh shake my head
lol laugh out loud
GOAT greatest of all time

Example: Deciphering Gen Z Lingo

# Replaces all abbreviations in text
# that are defined in more_slang
# with their full forms

def replace_slang(text):
    for abb in slang.keys():
        if abb in text:
            text = text.replace(abb, slang[abb])
    return text
replace_slang('smh, I did not lol')
'shake my head, I did not laugh out loud'
replace_slang('serena is the GOAT')
'serena is the greatest of all time'

Challenge 1

After running the following four lines of code, what are the values of numbers['1'], numbers['five'], numbers[1], and numbers[2]?

two = 1
numbers = {'1': 2}
numbers['five'] = 5
numbers[two] = numbers['1']
numbers[2] = numbers[1] + numbers['five']
numbers['1']
2
numbers['five']
5
numbers[1]
2
numbers[2]
7

Challenge 2: Nested Dictionaries

After defining bears, what are the values of: * bears['polar']['hungry'] * bears[None][1] * bears['weight_range']

bears = {
    'polar': {
        'color': 'white',
        'weight_range': [175, 700],
        'hungry': True
    },
    'grizzly': {
        'color': 'brown',
        'weight_range': [130, 360],
        'endangered': False
    },
    None: ['koala', 'panda']
}
bears['polar']['hungry']
True
bears[None][1]
'panda'
bears['weight_range']
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[30], line 1
----> 1 bears['weight_range']

KeyError: 'weight_range'