BYU logo Computer Science

Dictionaries, Part 3 (+tuples, + sorting, +state machines)

So far we have created dictionaries and added items to dictionaries, now we need to loop over them.

Two methods: keys() and values()

dictionary keys and values

keys() returns a dict_keys object that contains a list of keys

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

fruits = fruit_prices.keys()
# this is not actually a list
# it is actually a dict_keys object that automatically changes every time the dictionary keys change
print(fruits)

fruit_prices['plum'] = 0.10

print(fruits)
    dict_keys(['banana', 'apple', 'pear', 'peach', 'apricot', 'pineapple'])
    dict_keys(['banana', 'apple', 'pear', 'peach', 'apricot', 'pineapple', 'plum'])

you can iterate over the dictionary keys

# for you, the prices are double
fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}
for fruit in fruit_prices.keys():
    print(f"The {fruit} costs ${fruit_prices[fruit]*2}")
    The banana costs $1.0
    The apple costs $1.5
    The pear costs $2.0
    The peach costs $3.0
    The apricot costs $0.5
    The pineapple costs $6.0

values() returns a dict_values object that contains a list of values

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

prices = fruit_prices.values()
# this is not actually a list
# it is actually a dict_values object that automatically changes every time the dictionary values change
print(prices)

fruit_prices['plum'] = 0.10

print(prices)
    dict_values([0.5, 0.75, 1.0, 1.5, 0.25, 3.0])
    dict_values([0.5, 0.75, 1.0, 1.5, 0.25, 3.0, 0.1])

you can iterate over the dictionary values

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

for price in fruit_prices.values():
    print(price)
    0.5
    0.75
    1.0
    1.5
    0.25
    3.0

Tuples

A tuple is ordered and immutable

  • like a list, but you can’t change it
fruits = ("apples", "bananas", "cherry")

print(fruits)
print(f"I like to eat, eat, eat {fruits[0]} and {fruits[1]}!")
    ('apples', 'bananas', 'cherry')
    I like to eat, eat, eat apples and bananas!

You can’t change tuples!

fruits = ("apples", "bananas", "cherry")

# can't change it!
fruits[0] = 'apricots'
    ---------------------------------------------------------------------------

    TypeError                                 Traceback (most recent call last)

    /var/folders/9x/cb134v3d2nb22_rksynbspqm0000gn/T/ipykernel_27566/3571995762.py in <module>
          2
          3 # can't change it!
    ----> 4 fruits[0] = 'apricots'


    TypeError: 'tuple' object does not support item assignment

Tuples are super helpful when you want to return more than one item from a function

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

def lookup_price(fruit_prices, fruit):
    return (fruit, fruit_prices[fruit])

result = lookup_price(fruit_prices, 'peach')
print(result[0], result[1])
    peach 1.5

You can unpack tuples!

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

def lookup_price(fruit_prices, fruit):
    return (fruit, fruit_prices[fruit])

fruit, price = lookup_price(fruit_prices, 'peach')
print(f"A {fruit} costs ${price}.")
    A peach costs $1.5.

Dictionary items

items() returns a dict_items object that contains a list of tuples

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

items = fruit_prices.items()
print(items)

# dict_items automatically changes every time the dictionary keys change
fruit_prices['plum'] = 0.10

print(items)
    dict_items([('banana', 0.5), ('apple', 0.75), ('pear', 1.0), ('peach', 1.5), ('apricot', 0.25), ('pineapple', 3.0)])
    dict_items([('banana', 0.5), ('apple', 0.75), ('pear', 1.0), ('peach', 1.5), ('apricot', 0.25), ('pineapple', 3.0), ('plum', 0.1)])

You can iterate over the dictionary items

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

# for you the prices are half off
for item in fruit_prices.items():
    print(f"The {item[0]} costs ${item[1]/2}.")
    The banana costs $0.25.
    The apple costs $0.375.
    The pear costs $0.5.
    The peach costs $0.75.
    The apricot costs $0.125.
    The pineapple costs $1.5.

You can unpack the items as you iterate!

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

# for you the prices are half off
for fruit, price in fruit_prices.items():
    print(f"The {fruit} costs ${price/2}.")
    The banana costs $0.25.
    The apple costs $0.375.
    The pear costs $0.5.
    The peach costs $0.75.
    The apricot costs $0.125.
    The pineapple costs $1.5.

You can’t use indexing on dict_keys, dict_values, or dict_items unless you turn them into a regular list first

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

items = fruit_prices.items()
first_item = list(items)[0]
print(first_item)
    ('banana', 0.5)

Sorting lists and list-like objects

Use the sorted() method to sort a list or a list-like object (keys, values, items)

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

for fruit, price in sorted(fruit_prices.items()):
    print(f"The {fruit} costs ${price/2}.")

names = ['John', 'Ezekiel', 'Abby', 'Ellen']
print(sorted(names))
    The apple costs $0.375.
    The apricot costs $0.125.
    The banana costs $0.25.
    The peach costs $0.75.
    The pear costs $0.5.
    The pineapple costs $1.5.
    ['Abby', 'Ellen', 'Ezekiel', 'John']

State Machine Pattern

State Machine Pattern

  • initialize a state variable
  • loop over the elements
    • check and potentially update the state
  • use the state variable to return the final result

Find the earliest letter in a word.

def find_earliest_letter(word):
    # initialize state variable
    earliest = None
    for letter in word:
        if earliest is None or letter < earliest:
            earliest = letter
            print(f"earliest letter is now {earliest}")
    return earliest

result = find_earliest_letter('zoomba')
print(result)
result = find_earliest_letter('zombie')
print(result)
    earliest letter is now z
    earliest letter is now o
    earliest letter is now m
    earliest letter is now b
    earliest letter is now a
    a
    earliest letter is now z
    earliest letter is now o
    earliest letter is now m
    earliest letter is now b
    b

Another state machine example: decode 'xxyy9H%vvv%2i%t6!'

  • get the first character after every digit
def decode(message):
    # accumulator variable
    result = ''
    # state variable
    get_next = False
    for character in message:
        if get_next:
            result += character
            get_next = False
        elif character.isdigit():
            get_next = True
    return result

message = decode('xxyy9H%vvv%2i%t6!')
print(message)
message = decode('abc!#$2C3S111100')
print(message)
    Hi!
    CS110

And another state machine example

  • count the number of duplicates in a list of numbers
def count_duplicates(numbers):
    # initialize count
    count = 0
    # keep track of previous number
    previous = None
    for number in numbers:
        if previous == number:
            # found a duplicate
            count += 1
        # reset previous
        previous = number
    return count

result = count_duplicates([1, 1, 2, 3, 3, 4, 4, 4, 4, 5])
print(result)
    5

Find the cheapest price

fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

def find_min_price(fruit_prices):
    values = fruit_prices.values()
    # assume the first price is the cheapest until we are proven wrong
    # need to convert the values to a list so we can get the first one
    min_price = list(values)[0]
    for price in values:
        if price < min_price:
            # update the new minimum price
            min_price = price
    return min_price

price = find_min_price(fruit_prices)
print(price)
    0.25

What if we want to find the name of the item that is the cheapest, in addition to the price?

  • We can use tuples!
fruit_prices = {'banana': 0.5, 'apple': 0.75, 'pear': 1.00, 'peach': 1.50, 'apricot': 0.25, 'pineapple': 3.00}

def find_min_price(fruit_prices):
    items = fruit_prices.items()
    # convert the items to a list and get the first one
    # we can assume the first item is the cheapest until we are proven wrong
    cheapest = list(items)[0]
    for fruit, price in items:
        # unpack the tuple
        cheapest_fruit, cheapest_price = cheapest
        if price < cheapest_price:
            # update the cheapest item
            cheapest = (fruit, price)
    # return a tuple
    return cheapest

# unpack the tuple
fruit, price = find_min_price(fruit_prices)

print(f"The cheapest item is the {fruit} that costs ${price}.")
    The cheapest item is the apricot that costs $0.25.