person = ('Harry', 'Potter')
date = ('February', 29, 2016)
type(person)
Tuples are similar to lists and strings in terms of most operations: subscripting, membership with in
, slicing, and use of len
:
person[1]
2016 in date
len(date)
date[:2]
Tuples are immutable: like strings, but differently from lists, tuples are immutable.
date[1] = 28
Tuples are used often in python to do multiple assignments in one single statement:
a, b = 0, 1
print a, b
0, 1
a, b
It turns out that doing multiple variable assignments in one step is useful (we'll see it later today with the method .items()
).
Dictionaries are collections that map keys to values:
daysOfMonth = {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 30,
'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31,
'Sep': 30, 'Oct': 30, 'Nov': 30} # one month is missing
daysOfMonth
Important Note: Dictionaries are unordered. Notice that the order we entered the key,value pairs differs from the value that was outputed.
Use subscripting to look up values associated with a key.
daysOfMonth['Jan']
Trying to look for a key that doesn't exist...
daysOfMonth['October']
Note: Indexing with 0, 1, ..., will not work, the same way 'October' didn't work, because subscription is based only on the keys.
scrabbleDct = {'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8,
'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1,
'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10}
Here is the old version of the scrabblePoints()
function that uses if, elif, else
statements.
def scrabblePoints(letter):
if letter in 'aeilnorstu':
return 1
elif letter in 'dg':
return 2
elif letter in 'bcmp':
return 3
elif letter in 'fhvwy':
return 4
elif letter in 'k':
return 5
elif letter in 'jx':
return 8
elif letter in 'qz':
return 10
return 0
scrabblePoints('j')
Your task: Write the scrabblePoints2()
function that uses the scrabbleDct
to look-up a value for a letter.
# Write the code here
def scrabblePoints2(letter):
if letter in scrabbleDct:
return scrabbleDct[letter]
else:
return 0
scrabblePoints('j')
d = dict() # creates an empty dict
d
Besides writing out the key: value
pairs as we did in daysOfMonth
, we can create a dictionary from a list of tuples
where every tuple is of length 2, with the first object an immutable one.
d = dict([('a', 1)]) # a list of tuples
d
A tuple that is not part of a list will not work:
dict(('a', 1))
By providing a list of two-element tuples, we can create dictionaries easily:
points = dict([('a', 1), ('b', 3), ('c', 3), ('d', 2), ('e', 1)])
points
What happens when we use tuples that are not exactly length 2, or have mutable objects in the first index?
short_tup = ('Hermione Granger',)
dict([short_tup])
long_tup = ('Hermione Granger', 1, 2017, 'Gryffindor')
dict([long_tup])
list_tup = (['Hermione', 'Granger'], 2017)
dict([list_tup])
good_tup = ('Hermione Granger', 2017)
dict([good_tup])
In what situation might we want to create a dictionary from a list of tuples?
It turns out that we can easily generate list of tuples with code. Below is shown such a way, that uses the built-in function zip()
.
from string import lowercase # lowercase is the string, "abcdefghijklmnopqrstuvwxyz"
letters = list(lowercase)
scores = [1, 3, 3, 2, 1, 4, 2, 4, 1, 8, 5, 1, 3, 1, 1, 3, 10, 1, 1, 1, 1, 4, 4, 8, 4, 10]
print dict(zip(letters, scores))
Let's unpack what happened above:
print "lowercase ->", lowercase
print "letters ->", letters
print "zip output ->", zip(letters, scores)
Here are some easy examples of zip()
:
zip(range(5), 'abcde')
zip(range(5,10), range(20,15,-1))
Dictionaries are mutable:
daysOfMonth['Feb'] = 29 # change value associated with a key
daysOfMonth
daysOfMonth['Dec'] = 31 # add new key and value
daysOfMonth
However, keys of dictionaries must be immutable.
daysOfMonth[['Feb', 2015]] = 28 # try to use a key that has month and year in a list
# but this works, because a tuple is "immutable"
daysOfMonth[('Feb', 2015)] = 28
daysOfMonth
What does "unhashable" mean?
hash
¶When Python stores the keys of a dictionary in memory, it stores their hashes, which is an integer returned by the hash()
function. Only immutable objecs can be hashed.
hash("Wellesley")
hash(['Feb', 2015])
Don't have to worry about why the keys are hashed, or how the hash()
function works!
A dictionary object has several methods that either query
the state of the object, or modify
its state.
We show below several examples that are summarized in slide 10-19.
daysOfMonth = {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 30,
'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31,
'Sep': 30, 'Oct': 30, 'Nov': 30} # one month is missing
daysOfMonth # the entire dict
daysOfMonth.keys() # a list of keys only
daysOfMonth.values() # a list of values only
daysOfMonth.items() # a list of tuples for key and value
daysOfMonth.pop('Sep')
daysOfMonth
rest = {'Sep': 30, 'Dec': 31}
daysOfMonth.update(rest)
daysOfMonth
daysOfMonth.clear()
daysOfMonth
There are many ways to iterate over a dictionary:
.keys()
).values()
).items()
)phones = {5558671234: 'Justin Bieber', 9996541212: 'Shakira', 7811234567: 'Kim Bottomly'}
# iterate directly (by default Python goes over the keys, because they are unique)
for key in phones:
print key, phones[key]
for key in phones.keys():
print key, phones[key]
for val in phones.values():
print val
Question: Can we go from values to keys, as we did from keys to values? What can we say about keys and values in a dictionary?
daysOfMonth = {'Jan': 31, 'Feb': 28, 'Mar': 31, 'Apr': 30,
'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31,
'Sep': 30, 'Oct': 31, 'Nov': 30, 'Dec': 31}
Answer: Going from values to keys is more complicated and there is no straighforward way as the subsripting we used for the keys.
This is because the keys are unique and we know that there is a one-to-one mapping from keys to values. However, as you can see in the
dictionary daysOfMonth
, a value, for example 30, corresponds to many keys, so the program cannot know which one the user needed.
for item in daysOfMonth.items():
print item
Multiple variable assignments
for key, val in daysOfMonth.items():
print key, "has", val, "days"
def frequencies(wordList):
"""Given a list of words, returns a dictionary of word frequencies"""
# create an empty dict
# iterate through the words of the list
# set the value or update the value for each word
freqs = {}
for word in wordList:
if word in freqs:
freqs[word] += 1
else:
freqs[word] = 1
return freqs
frequencies('I know that I said that I did'.split())
.get()
¶The method .get()
is used to avoid the step of checking for a key before updating.
This is possible because this method will return a "default" value when the key is not in the dictionary.
In all other cases, it will return the value associated with the given key.
daysOfMonth.get('Oct', 'unknown')
daysOfMonth.get('OCT', 'unknown')
frequencies
to use .get()
¶def frequencies2(wordList):
"""Given a list of words, returns a dictionary of word frequencies"""
# create an empty dict
# iterate through the words of the list
# set the value or update the value for each word
freqs = {}
for word in wordList:
freqs[word] = freqs.get(word, 0) + 1
return freqs
frequencies2('I know that I said that I did'.split())
Write the function getKeyWithMaxValue()
that behaves as shown below:
In [2]: getKeyWithMaxValue({'A': 0.25, 'E': 0.36,
'I': 0.16, 'O': 0.18, 'U': 0.05})
Out[2]: 'E'
Hint: Remember the built-in function max()
.
def getKeyWithMaxValue(dct):
"""Given a dict whose values are numbers, return the key that
corresponds to the highest value.
"""
# enter your code
maxVal = max(dct.values()) # find max value among all values
for key in dct:
if dct[key] == maxVal:
return key # early return
getKeyWithMaxValue({'A': 0.25, 'E': 0.36, 'I': 0.16, 'O': 0.18, 'U': 0.05})
If you solved Ex. 4 with a for loop, try now an approach without a for loop.
Hint: Remember the buil-in function zip()
we introduced earlier.
def getKeyWithMaxValue2(dct):
"""Given a dict whose values are numbers, return the key that
corresponds to the highest value.
"""
# enter your code
pairs = zip(dct.values(), dct.keys())
maxPair = max(pairs)
return maxPair[1] # this will have the key, since the first item is the value
getKeyWithMaxValue2({'A': 0.25, 'E': 0.36, 'I': 0.16, 'O': 0.18, 'U': 0.05})
Write a function that takes a dict that has many similar values and creates a new dict where the keys are the unique values and
the values are lists of the keys.
Example:
In [30]: disneyOlympicResults = {'mickey': 'silver', 'minnie': 'gold',
'donald': 'bronze', 'daisy': 'bronze',
'goofy': 'bronze', 'ariel': 'silver',
'nemo': 'gold', 'mulan': 'silver', 'elsa': 'gold'}
In [31]: reverseDictionary(disneyOlympicResults)
Out[31]:
{'bronze': ['donald', 'goofy', 'daisy'],
'gold': ['elsa', 'nemo', 'minnie'],
'silver': ['mickey', 'mulan', 'ariel']}
def reverseDictionary(dct):
"""Given a dict that has many similar values, returns a new dict where
the keys are the unique values and the values are lists of the keys.
"""
reverseD = {}
for key, value in dct.items():
if value not in reverseD:
reverseD[value] = [key]
else:
reverseD[value].append(key)
return reverseD
disneyOlympicResults = {'mickey': 'silver', 'minnie': 'gold',
'donald': 'bronze', 'daisy': 'bronze',
'goofy': 'bronze', 'ariel': 'silver',
'nemo': 'gold', 'mulan': 'silver', 'elsa': 'gold'}
reverseDictionary(disneyOlympicResults)