Today: dict and dict-count (however far we get today)

Dict - Hash Table - Fast

Dict Story Arc

Dict Basics

See Python Guide for more detail: Python Dict

alt:python dict key/value pairs 'a'/'alpha' 'g'/'gamma' 'b'/'beta'

Dict Code Example 1

>>> d = {}             # Start with empty dict {}
>>> d['a'] = 'alpha'   # Set key/value
>>> d['g'] = 'gamma'
>>> d['b'] = 'beta'
>>> # Now we have built the picture above
>>>
>>> d['g']             # Get by key
'gamma'
>>> d['b']
'beta'
>>> d['a'] = 'apple'   # Overwrite 'a' key
>>> d['a']
'apple'
>>>
>>> # Dict literal format, curl-braces, key:value
>>> d
{'a': 'apple', 'g': 'gamma', 'b': 'beta'}
>>>

Dict - Errors, in Test

Dict Code Example 2

>>> # Can initialize dict with literal
>>> d = {'a': 'alpha', 'g': 'gamma', 'b': 'beta'}
>>>
>>> d['x']             # Key not present -> Error
Error:KeyError('x',)
>>>
>>> 'a' in d           # "in" key tests
True
>>> 'x' in d
False
>>> 'alpha' in d       # NO in/value does not work
False                  # get/set/in use **key** only
>>>
>>> # Can use += to do a get/set modification
>>> d['a'] += '!!!'
>>> d['a']
'alpha!!!'
>>> 

Key and Value - Different Roles

Dict = Memory

Dict vs. List - Keys

Dict Memory Example - Meals

Use dict to remember that 'breakfast' is 'apple' and 'lunch' is 'donut'. Using 'breakfast' and 'lunch' as keys.

>>> meals = {}
>>> meals['breakfast'] = 'apple'
>>> meals['lunch'] = 'donut'
>>>
>>> # time passes, other lines run
>>>
>>> # what was lunch again?
>>> meals['lunch']
'donut'
>>> 
>>> # did I have breakfast or dinner?
>>> 'breakfast' in meals
True
>>> 'dinner' in meals
False
>>>

Basic Dict Code Examples - Meals

Look at the dict1 "meals" exercises on the experimental server

> dict1 meals exercises

With the "meals" examples, the keys are 'breakfast', 'lunch', 'dinner' and the values are like 'hot dot' and 'bagel'. A key like 'breakfast' may or may not be in the dict, so need to "in" check first.

Tricky case: dict[key]

The code can only get the value for a key, if the key is in the dict. Otherwise it's an error. Therefore, need to structure the code with an "in" check or something to make sure the key is in the dict before trying to get its value.

bad_start() Solution Code

Question: is the meals['breakfast'] == 'candy' line safe? Yes. The if-statement above screens out the case that the 'breakfast' key is not in the dict.

def bad_start(meals):
    if 'breakfast' not in meals:
        return True
    if meals['breakfast'] == 'candy':
        return True
    return False
    # Can be written with "or" / short-circuiting avoids key-error
    # if 'breakfast' not in meals or meals['breakfast'] == 'candy':

enkale() Solution Code

Demo: work out the code, see key error

Cannot access meals['dinner'] in the case that dinner is not in the dict, so need logic to avoid that case.

def enkale(meals):
    if 'dinner' in meals and meals['dinner'] == 'candy':
        meals['dinner'] = 'kale'
    return meals

The "in" check guards the meals['dinner'] access, since the short-circuit and only proceeds when the first test is True. Could write it out in this longer form which is ok - works exactly the same as the and/short-circuit form:

def enkale(meals):
    if 'dinner' in meals:
        if meals['dinner'] == 'candy':
            meals['dinner'] = 'kale'
    return meals

"in" Guard Pattern


We'll just get started with this topic .. pick up on Wed

Dict-Count Algorithm

Dict Count Code Examples

> dict2 Count exercises

Note: not using += on the server for these - it's temporarily broken!

Dict-Count Steps

Dict-Count abacb

Go through these data items: a b a c b

Sketch out counts dict here:

Counts dict ends up as {'a': 2 'b': 2, 'c': 1}:

alt: counts a 2 b 2 c 1

1. str-count1() - if/else

str_count1 demo, canonical dict-count algorithm

Solution code

def str_count1(strs):
    counts = {}
    for s in strs:
        # s not seen before?
        if s not in counts:
            counts[s] = 1   # first time
        else:
            counts[s] = count[s] + 1  # every later time
    return counts

2. str-count2() - "Invariant" Version, no else

Standard Dict-Count Code - "invariant" Version

def str_count2(strs):
    counts = {}
    for s in strs:
        if s not in counts:  # fix counts/s if not seen before
            counts[s] = 0
        # Invariant: now s is in counts one way or
        # another, so can do next step unconditionally
        counts[s] = count[s] + 1
    return counts

Int Count - Exercise

Apply the dict-count algorithm to a list of int values, return a counts dict, counting how many times each int value appears in the list.

Char Count - Exercise

Apply the dict-count algorithm to chars in a string. Build a counts dict of how many times each char appears in a string so 'Coffee' returns {'c': 1, 'o': 1, 'f': 2, 'e': 2}.