import random
twos, threes, fours, fives, sixes = 0, 0, 0, 0, 0
for i in range(1000):
roll = random.randint(1,3) + random.randint(1,3)
if roll == 2:
twos += 1
if roll == 3:
threes += 1
if roll == 4:
fours += 1
if roll == 5:
fives += 1
if roll == 6:
sixes += 1
print("twos: %s, threes: %s, fours: %s, fives: %s, sixes %s" % (twos, threes, fours, fives, sixes))
Whew!
That was a long if-else. What if we had to write one for two twenty-sided dice?
If there were only a way to dynamically create names and associate values to them.
We'll get to that in a second. First: compound types, mapping types and dictionaries…
Compound types: values that are made up of other values.
Sequence types are compound types. We know three sequence types. What are they?
Another kind of compound type is a mapping type.
A mapping type is a data type that is made of a collection of keys (think of names) and their associated values. The only mapping type in Python is a dictionary.
A dictionary is an unordered collection of key/value pairs.
Let's take a look at some examples
{"first_name":"joe", "fav_candy":"cleo's"}
{28:"foo", 6:"bar", "entirely different":["baz"]}
{}
(btw, cleo's are pretty good)
What are the keys and what type are they? What are the values and what type are they?
d1 = {"first_name":"joe", "fav_candy":"cleo's"}
d2 = {28:"foo", 6:"bar", "entirely different":["baz"]}
You can use the key like a list index to retrieve a value at that key. What does this code print out?
d = {"first_name":"joe", "fav_candy":"cleo's"}
print(d["first_name"])
print(d["fav_candy"])
joe
cleo's
Let's try that again… but with a key that doesn't exist. What do you think will happen here?
d = {"first_name":"joe", "fav_candy":"cleo's"}
print(d["height"])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'height'
You can also retrieve a value from a dictionary by calling the get method. get takes two arguments:
What do you think this code outputs?
d = {"first_name":"joe", "fav_candy":"cleo's"}
print(d.get("height", None))
None
So… things are a bit different when adding keys and values to a dictionary. There is no error if you use a key that doesn't exist in order to assign a value to it (that is… to create a new key/value pair).
# look ma, no keys!
d = {}
# but I can assign with no probz
d["problems"] = None
d["another key"] = "another value"
If the key already exists… and you use the assignment operator, you are just associating a new value with an existing key.
What does this code output?
d = {}
d["another key"] = "another value"
d["problems"] = None
d["another key"] = "something"
print(d["another key"])
print(d["problems"])
something
None
Based on what we've seen so far… are dictionaries mutable or immutable?
Dictionaries are mutable!
d = {}
d["did not exist before"] = "some value"
# ok!
Let's run this code. What would you expect this to print? Does it match what actually happens?
d = {"first_name":"joe", "fav_candy":"cleo's"}
for item in d:
print(item)
# we only get the keys!
fav_candy
first_name
Another way to iterate over a dictionary is to convert it to a special sequence called a dictionary view.
What type is the type of variable, i? How many iterations are there? What is the value of i at each iteration?
d = {"first_name":"joe", "fav_candy":"cleo's"}
items = d.items()
for t in items:
print(t)
d = {"first_name":"joe", "fav_candy":"cleo's"}
items = d.items()
for t in items:
print(t)
A few notes….
Now… we have a tuple… how do we print out each key and value individually (how do we unpack again?)
d = {"first_name":"joe", "fav_candy":"cleo's"}
for k, v in d.items():
print(k, v)
Unlike sequence types like string, list or tuple, dictionaries are unordered. That means that the order of the key value pairs cannot be guaranteed! Let's take a look. Intuitively, what's the first thing that we think will be printed out?
d = {"one":"foo", "two":"bar", 3:"baz"}
for k, v in d.items():
print(k, v)
# this is actually just one possible ordering!
3 baz
two bar
one foo
The in and not in operators work with dictionary keys; len() gives back the number of key/value pairs →
pizza = {"crust":"thin", "topping":"mushrooms", 'size':'large', 'sauce':'tomato'}
print(len(pizza))
# prints out 4
result = 'crust' in pizza
print(result)
# prints out True
By the way, here are a few more dictionary methods:
values and keys give back dictionary views (they essentially act like lists) of either all values or all keys of the dictionary that they're called on. What does this output? →
vehicle = {"name":"bathysphere", "wheels":0, "can fly":False}
print(vehicle.keys())
print(vehicle.values())
Note that the order of the keys and values cannot be guaranteed!
dict_keys(['can fly', 'wheels', 'name'])
dict_values([False, 0, 'bathysphere'])
pop removes and returns the item at the key specified. What does this output?→
vehicle = {"name":"bathysphere", "wheels":0, "can fly":False}
result1 = vehicle.pop('can fly')
result2 = vehicle.pop('floats', False)
print(result1)
print(result2)
print(vehicle)
False
False
{'wheels': 0, 'name': 'bathysphere'}
popitem removes and returns an arbitrary key/value pair. What does this output?→
vehicle = {"name":"bathysphere", "wheels":0, "can fly":False}
result1 = vehicle.popitem()
print(result1)
print(vehicle)
Note that the key/value pair removed and returned will not always be the same!
('can fly', False)
{'wheels': 0, 'name': 'bathysphere'}
update adds key/value pairs (or updates values if keys already exist) from another dictionary to the dictionary that update is called on. What does this output?→
vehicle = {"name":"bathysphere", "wheels":0, "can fly":False}
another_vehicle = {'can float':True, 'name':'boat'}
vehicle.update(another_vehicle)
print(vehicle)
{'can fly': False, 'wheels': 0, 'name': 'boat', 'can float': True}
To change a value base on an existing value, such as incrementing a number, you can simply do something like this (adds one to the current value at fga):
d = {'fgm':1, 'fga':2}
d['fga'] = d['fga'] + 1
But what if it doesn't exist yet? What happens here? →
d = {'fgm':1 }
d['fga'] = d['fga'] + 1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'fga'
Try reimplementing our dice program so that it uses a dictionary to store the frequency of rolls (each roll as a key, each value as a count). (hint: use in, the get method or a try-except to deal with keys that don't exist).
import random
twos, threes, fours, fives, sixes = 0, 0, 0, 0, 0
for i in range(1000):
roll = random.randint(1,3) + random.randint(1,3)
if roll == 2:
twos += 1
if roll == 3:
threes += 1
if roll == 4:
fours += 1
if roll == 5:
fives += 1
if roll == 6:
sixes += 1
print("twos: %s, threes: %s, fours: %s, fives: %s, sixes %s" % (twos, threes, fours, fives, sixes))
import random
freq_dice_rolls = {}
for i in range(1000):
roll = random.randint(1,3) + random.randint(1,3)
freq_dice_rolls[roll] = freq_dice_rolls.get(roll, 0) + 1
print(freq_dice_rolls)