### CS51A - Spring 2019 - Class 13

#### Example code in this lecture

dictionaries.py

#### Lecture notes

- mentor hours and office hours changing

• write a function called read_numbers that takes a file of numbers (one per line) and generates a list consisting of the numbers in that file
- look at read_numbers function in dictionaries.py code
- if you're reading numbers, don't forget to turn them into ints using "int"

>>> data = read_numbers('numbers.txt')
data
[1, 2, 3, 2, 1, 1, 2, 6, 7, 8, 10, 1, 5, 5, 5, 3, 8, 6, 7, 6, 4, 1, 1, 2, 3, 1, 2, 3]

• what if we wanted to find the most frequent value in this data?
- how would you do it?
- do it on paper: [1, 2, 3, 2, 3, 2, 1, 1, 5, 4, 4, 5]
- how did you do it?
- kept a tally of the number
- each time you saw a new number, added it to your list with a count of 1
- if it was something you'd seen already, add another tally/count
- key idea, keeping track of two things:
- a key, which is the thing you're looking up
- a value, which is associated with each key

• dictionaries (aka maps)
- store keys and an associated value
- each key is associated with a value
- lookup can be done based on the key
- this is a very common phenomena in the real world. What are some examples?
- social security number
- key = social security number
- value = name, address, etc
- phone numbers in your phone (and phone directories in general)
- key = name
- value = phone number
- websites
- key = url
- value = location of the computer that hosts this website
- car license plates
- key = license plate number
- value = owner, type of car, ...
- flight information
- key = flight number
- value = departure city, destination city, time, ...
- creating new dictionaries
- dictionaries can be created using curly braces
>>> d = {}
>>> d
{}
- dictionaries function similarly to lists, except we can put things in ANY index and can use non-numerical indices
>>> d[15] = 1
>>> d
{15: 1}

- notice when a dictionary is printed out, we get the key AND the associated value

>>> d[100] = 10
>>> d
{100: 10, 15: 1}
>>> my_list = []
>>> my_list[15] = 1
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
IndexError: list assignment index out of range

- dictionaries ARE very different than lists....
- we can also update the values already in a list
>> d[15] = 2
>>> d
{100: 10, 15: 2}
>>> d[100] += 1
>>> d
{100: 11, 15: 2}
- keys in the dictionary can be ANY immutable object
>>> d2 = {}
>>> >>> d2["dave"] = 1
>>> d2["anna"] = 1
>>> d2["anna"] = 2
>>> d2["seymore"] = 100
>>> d2
{'seymore': 100, 'dave': 1, 'anna': 2}
- the values can be ANY object
- >>> d3 = {}
>>> d3["dave"] = []
>>> d3
{'dave': []}
>>> d3["dave"].append(1)
>>> d3["dave"].append(40)
>>> d3
{'dave': [1, 40]}
- be careful to put the key in the set before trying to use it
>>> d3["steve"]
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
KeyError: 'steve'
>>> d3["steve"].append(1)
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
KeyError: 'steve'
- how do you think we can create non-empty dictionaries from scratch?
>>> another_dict = {"dave": 1, "anna":100, "seymore": 21}
>>> another_dict
{'seymore': 21, 'dave': 1, 'anna': 100}
- what are some other methods you might want for dictionaries (things you might want to ask about them?
- does it have a particular key?
- how many key/value pairs are in the dictionary?
- what are all of the values in the dictionary?
- what are all of the keys in the dictionary?
- remove all of the items in the dictionary?
- dictionaries support most of the other things you'd expect them too that we've seen in other data structures
>>> "seymore" in another_dict
True
>>> len(another_dict)
3
- dictionaries are a class of objects, just like everything else we've seen (called dict ... short for dictionary)
>>> help(dict)
- some of the more relevant methods:
>>> d2
{'seymore': 100, 'dave': 1, 'anna': 2}
>>> d2.values()
[100, 1, 2]
>>> d2.keys()
dict_keys(['seymore', 'dave', 'anna'])
>>> d2.pop('seymore')
>>> d2
{'dave': 1, 'anna': 2}
>>> d2.clear()
>>> d2
{}

• generating counts
- We're going to use dictionaries to store counts like we did on paper
- Write a function called get_counts that takes a list of numbers and returns a dictionary containing the counts of each of the numbers
- Key idea:

def get_counts(numbers):
d = {}

for num in numbers:
# do something here

return d

- There are two cases we need to contend with:
1) if the number isn't in the dictionary

- In this case we need to add it with the value 1

d[num] = 1

2) if the number is in the dictionary

- In this case, we just need to increment it

d[num] = d[num] + 1

which can also be written

d[num] += 1

- Look at the get_counts function in dictionaries.py code

- We now can generate the counts from our file

>>> data = read_numbers('numbers.txt')
>>> data
>>> [1, 2, 3, 2, 1, 1, 2, 6, 7, 8, 10, 1, 5, 5, 5, 3, 8, 6, 7, 6, 4, 1, 1, 2, 3, 1, 2, 3]
>>> get_counts(data)
{1: 7, 2: 5, 3: 4, 6: 3, 7: 2, 8: 2, 10: 1, 5: 3, 4: 1}

• Iterating over dictionaries
- We're almost to the point where we can find the most frequent value.
- Next, we need to go through all of the values in the dictionary to find the most frequent one.

- there are many ways we could iterate over the things in a dictionary
- iterate over the values
- iterate over the keys
- iterate over the key/value pairs
- which one is most common?
- since lookups are done based on the keys, iterating over the keys is the most common
- by default, if you say:

for key in dictionary:
...

key will get associated with each key in the dictionary.
- once we have the key, we can use it to lookup the value associated with that key and do whatever we want with the pair
for key in dictionary:
value = dictionary[key]
..

- look at the print_counts function in dictionaries.py code
- "\t" is the tab character

>>> data = read_numbers('numbers.txt')
>>> counts = get_counts(data)
>> print_counts(counts)
1   7
2   5
3   4
6   3
7   2
8   2
10   1
5   3
4   1

Notice that there the keys are not in numerical order. In general, there's no guarantee about the ordering of the keys, only that you'll iterate over all of them.

• look at the get_most_frequent_value function in dictionaries.py code
- Looks very similar to the my_max function we wrote in lecture8 (http://www.cs.pomona.edu/~dkauchak/classes/cs51a/lectures/lecture8-sequences.html)
- We keep a variable (max_value) that stores the largest value we've seen so far
- We'll initialize it to -1 assuming that the numbers are all positive
- See problem set 6 for a general solution
- We then iterate through each of the key/value pairs in our dictionary
- We compare the value (i.e. counts[key]) to the largest value we've seen so far
- If it's larger, we update max_value
- The only difference with my_max is that we want to return the *key* associated with the largest value
- We need another variable (max_key) that stores this key
- Whenever we update max_value, we also update max_key

>>> data = read_numbers('numbers.txt')
>>> get_most_frequent_value(data)
1

• It may also be useful to not only get the most frequent value, but also how frequent it is
- Anytime you want to return more than one value from a function, a tuple is often a good option
- Look at the get_most_frequent function in dictionaries.py code
- only difference is that we return a tuple and also include the max_value

>>> data = read_numbers('numbers.txt')
>>> get_most_frequent(data)
(1, 7)