Week 13: dictionaries

Monday

The video from today’s lecture (Monday, April 27, 2020):

And here are the announcements:

  • Lab 11 is up and due Saturday (May 2)

  • Quiz 6 is next week

  • I will send out grade reports on Wednesday

This week we are finishing objects, learning a little about dictionaries, and wrapping up the class! :(

the Contact object

Last time we wrote a Contact object:

class Contact(object):
    """Contact Class"""

    def __init__(self):
        """constructor for empty contact objects"""
        self.last = ""    # last name
        self.first = ""   # first name
        self.email = ""
        self.phone = ""

    def __str__(self):
        """should return a string..."""
        s = "%s, %s -- %s, %s" % (self.last, self.first,
                self.email, self.phone)
        return s

    def setLast(self, lastname):
        """setter for last name"""
        self.last = lastname
    def setFirst(self, firstname):
        """setter for first name"""
        self.first = firstname
    def setEmail(self, email):
        """setter for email"""
        self.email = email
    def setPhone(self, phone):
        """setter for phone"""
        self.phone = phone

What happens if we try to sort() a list of Contact objects?

>>> from contact import *
>>> c1 = Contact("Jeff Knerr")
>>> c2 = Contact("Lisa Meeden")
>>> c3 = Contact("Aline Normoyle")
>>> clist = [c1,c2,c3]
>>> clist.sort()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '<' not supported between instances of 'Contact' and 'Contact'

Looks like the built-in python sort() list method doesn’t know how to compare our Contact objects! We need the "less-than" operator for our objects. How do we want to say one object is less than another? One way is by comparing last names:

    # add a < operator
    def __lt__(self, other):
        """add in ability to compare with < operator"""
        return self.last < other.last

By adding this special method to our class we are telling python how to know one object is less than another (using the self.last instance variable). And just by adding that method, the sort now works!

python’s sorted() function

At the bottom of contacts.py is a website with python sorting documentation. Another option for sorting a list of objects is to use attrgetter and the sorted() function:

    from operator import attrgetter

    byfirst = sorted(contacts, key=attrgetter('first'))
    byphone = sorted(contacts, key=attrgetter('phone'))

The sorted() function returns a new list. The above two lines are sorting the contacts list, which is a list of Contact objects. The first line sorts the list by the self.first attribute (or instance variable), and the second sorts it by self.phone.

python dictionaries

A dictionary in python is a data structure for storing key:value pairs. Examples of these might be: key=word, value=definition, or key=social security number, value=info about the person with that SSN, or key=phone number, value=full name of person with that phone number. The key is unique, and you use the key to look up/access the value in the dictionary.

dictionary syntax

Here’s a quick look at the syntax for dictionaries:

>>> e2s = {"man":"hombre", "bye":"adios", "yes":"si"}
>>> print(e2s)
{'man': 'hombre', 'bye': 'adios', 'yes': 'si'}
>>> e2s["yes"]
'si'
>>> e2s["bye"]
'adios'
>>> e2s["hello"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'hello'
>>> e2s["hello"] = "hola"
>>> print(e2s)
{'man': 'hombre', 'bye': 'adios', 'yes': 'si', 'hello': 'hola'}
>>> len(e2s)
4
>>> "man" in e2s
True
>>> "thanks" in e2s
False

On the first line I manually define a dictionary (e2s) with a few key:value pairs. I then use the e2s[key] syntax to get the values back for certain keys. A KeyError results if the key I try is not found in the dictionary. I can also add new key:value pairs with the e2s[newkey]=value syntax. Using an existing key would overwrite the current value. And finally, the in operator works for testing if a key is in the dictionary.

morse code example

Want to convert alphabetic characters into morse code? Here’s a dictionary for that:

    morse = {
        'a': '.-',
        'b':   '-...',
        'c':   '-.-.',
        'd':   '-..',
        'e':   '.',
        'f':   '..-.',
        'g':   '--.',
        'h':   '....',
        'i':   '..',
        'j':   '.---',
        'k':   '-.-',
        'l':   '.-..',
        'm':   '--',
        'n':   '-.',
        'o':   '---',
        'p':   '.--.',
        'q':   '--.-',
        'r':   '.-.',
        's':   '...',
        't':   '-',
        'u':   '..-',
        'v':   '...-',
        'w':   '.--',
        'x':   '-..-',
        'y':   '-.--',
        'z':   '--..'   }

With the above dictionary we can look up any lowercase alphabetic character and get back the morse code equivalent (see morse.py file in the w13 directory).

Wednesday

The video from today’s lecture (Wednesday, April 29, 2020):

review of dictionaries:

d = {}              # create emtpy dictionary
d[key] = value      # add key:value pair to dictionary
d = {1:"Lisa", 2:"Aline", 3:"Jeff"}   # create dictionary with key:value
                                      # pairs already given
d[key]      # will get value for that key
            # (and give error if no such key)
key in d    # "in" operator works for keys (returns True if key present)
len(d)      # returns how many keys in dictionary
d.keys()    # returns iterator on keys
            # (something we can use in a for loop)
for key in d.keys():
    print(key, d[key])      # would print out all key:value pairs

compare vs list-of-lists

Could use either of these in our duolingo program:

LOL = [['the milk', 'la leche'], ['the girl', 'la nina'], ['the apple', 'la manzana'], ['the boy', 'el nino'], ['i eat bread', 'yo como pan'], ['man', 'hombre'], ['woman', 'mujer'], ['you are', 'eres'], ['i am', 'soy'], ['the man drinks water', 'el hombre bebe agua'], ['he eats apples', 'el come manzanas'], ['i drink', 'yo bebo'], ['you drink', 'tu bebes'], ['he drinks', 'el bebe'], ['thanks', 'gracias'], ['bye', 'adios'], ['good night', 'buenas noches'], ['hello', 'hola'], ['nice to meet you', 'mucho gusto'], ['yes', 'si'], ['you are welcome', 'de nada'], ['good morning', 'buenos dias']]
dictionary = {'the milk': 'la leche', 'the girl': 'la nina', 'the apple': 'la manzana', 'the boy': 'el nino', 'i eat bread': 'yo como pan', 'man': 'hombre', 'woman': 'mujer', 'you are': 'eres', 'i am': 'soy', 'the man drinks water': 'el hombre bebe agua', 'he eats apples': 'el come manzanas', 'i drink': 'yo bebo', 'you drink': 'tu bebes', 'he drinks': 'el bebe', 'thanks': 'gracias', 'bye': 'adios', 'good night': 'buenas noches', 'hello': 'hola', 'nice to meet you': 'mucho gusto', 'yes': 'si', 'you are welcome': 'de nada', 'good morning': 'buenos dias'}

Why use a dictionary? Think about the lookup time for finding "hello" in the list-of-lists:

  • LOL lookup is O(N) or O(logN) if binary search

  • dictionary lookup is O(1)

A dictionary uses a hash function of the key:

>>> hash("jeff")
-8564366796957863749
>>> hash("Jeff")
-2663725661851044896
>>> hash("hello")
6799624814673269992

Given the key (e.g., "jeff"), we compute the hash(key) and that tells us where to find the value in the data structure. Very much like indexing: given an index, that tells us where to find the item in the list. Indexing is also O(1). But if you just have a word (like "hello"), looking that up in a list-of-lists requires O(N) or O(logN).

example

Add code to eng2spanish.py program to make the lookup and add options work:

$ python3 eng2spanish.py

[l] lookup
[a] add/change
[q] quit
Your choice? l
Word to look up? man
 --> hombre

[l] lookup
[a] add/change
[q] quit
Your choice? l
Word to look up? bye
 --> adios

[l] lookup
[a] add/change
[q] quit
Your choice? l
Word to look up? hello
Hmmm...I don't know that word.

[l] lookup
[a] add/change
[q] quit
Your choice? a
English word to add: hello
Spanish for hello: hola

[l] lookup
[a] add/change
[q] quit
Your choice? l
Word to look up? hello
 --> hola

[l] lookup
[a] add/change
[q] quit
Your choice? q

word counts

What are the most-used words in Romeo and Juliet?

The file "/usr/local/doc/romeoandjuliet.txt" contains Shakespeare’s "The Tragedy of Romeo and Juliet". Can you read in all words from that file and show the top 20 most-used words?

See wordcount.py for a start…​

Jul. O Romeo, Romeo! wherefore art thou Romeo?
Deny thy father and refuse thy name!
Or, if thou wilt not, be but sworn my love,
And I'll no longer be a Capulet.

Friday

The video from today’s lecture (Friday, May 1, 2020):

  • youtube video of zoom lecture

  • Last Class! :(

  • Lab 11 due Saturday

  • Quiz 6 Study Guide coming (quiz is May 7-12)

  • Will get Labs back to you next week

matplotlib

Learn some matplotlib

  • simple graph: simpleplot.py

  • bargraph: bargraph.py

Also see the matplotlib gallery

thank your ninjas!

THANK YOU Emma, Alex, and Sydney!!! THANK YOU Emma, Alex, and Sydney!!!