Lab: Association lists and searching

Friday, Nov 16, 2018
Lab writeups are due at 10:30pm on the day of the next class meeting. For example, a Wednesday lab is due at 10:30pm on Friday. Each lab writeup will be announced at the end of class on a lab day.
In today’s laboratory, you will experiment with association lists, structures that make it easy to look up information. You will work with two kinds of association lists: lists of color information, as described in the reading, and lists of shape descriptions, similar to the drawings we encountered earlier in the course.


a. Make a copy of association-lists-lab.rkt.

b. Review the definitions in that code to make sure you understand what procedures and values are being defined.


Exercise 1: Extracting attributes

a. As you’ll note from the provided code, we use “directory” to refer to an association list in which each entry is a list of the form '(last first username phone attribute-1 ... attribute-n).

Write 6P-style documentation for a procedure, (lookup-attributes last-name directory), that lets you find the attributes associated with a particular last name. The procedure should return #f if there is no element with tha tlast name.

For example,

> (lookup-attributes "Weinman" grinnell-directory-annotated)
'("CSC" "Chair" "Associate" "NSF Grant")
> (lookup-attributes "Smith" grinnell-directory-annotated)
> (lookup-attributes "Kington" grinnell-directory-annotated)

You may wish to consult the documentation for assoc and lookup-email-by-last-name to guide you.

b. Write the procedure lookup-attributes using assoc to do the searching.

Note: Since you are using assoc to do the searching, your goal is primarily to extract the attributes once you’ve found the appropriate entry.

Hint: The goal of this procedure is similar to the goal of lookup-email-by-last-name. You may consider using the definition of that procedure as a model for designing this procedure. If you do, remember to give an appropriate citation.

Exercise 2: Cartoon sidekicks

a. Define an association list, sidekicks, that associates the names of some famous cartoon protagonists (as strings) with the names of their sidekicks (again, as strings).

You may also want to look at the note on this exercise.

Here’s a table containing information for your association list:

Protagonist Sidekick
Peabody Sherman
Yogi Booboo
Secret Squirrel Morocco Mole
Tennessee Tuxedo Chumley
Quick Draw McGraw Baba Looey
Dick Dastardly Muttley
Bullwinkle Rocky
Bart Simpson Milhouse Van Houten
Asterix Obelix
Strong Bad The Cheat

b. Use the assoc procedure to search the sidekicks association list for someone who is on the list and for someone who is not on the list.

Exercise 3: Duplicate keys

a. Redefine sidekicks so that it includes two entries with the same protagonist and different sidekicks – say Scooby Doo, who has both Shaggy and Scrappy Doo as sidekicks. What do you expect to happen if you try to apply assoc to retrieve these entries, using the common key "Scooby Doo"?

b. Check your answer experimentally.

c. Many people find these results disappointing. To help alleviate this disappointment, define and test a recursive procedure, (assoc-all key alist), similar to assoc, except that it returns a list of all the lists with the given key.

Exercise 4: Reverse associations

a. What happens if you search the hero/sidekick list by sidekick instead of by protagonist? For example, you might try

> (assoc "Chumley" sidekicks)

b. Define and test a recursive procedure (assoc2 val alist) that returns

  • an element from alist that has val as its second component, if such an element exists;
  • #f if there is no such element.

c. Define and test a recursive procedure that takes two parameters, an association list, alist, and an associated datum, val, and returns a list of all elements that have val as the second component. You may assume that all elements of alist are lists of at least two elements.

Exercise 5: Compound keys

Suppose we add the following entries to the end of the College directory.

   (list "Moore"           "Emily"   "emoore"       "4205"
         "MAT" "Emeritus" "CSC")
   (list "Moore"           "Tom"     "tmoore"       "0000"
         "Statistics" "Emeritus" "MAT")
   (list "Moore"           "Orless"  "punny"        "1234"
         "CSC" "Emeritus" "Fictitious" "NSF Grant")

As you’ve found, when there are multiple elements with the same key, assoc returns the first. For situations like that, we might want to have a compound key, consisting of the first and last name.

Write a procedure (lookup-phone-by-name name directory) that looks someone up by the full name in the directory.

> (lookup-phone-by-name "Tom Moore" grinnell-directory-annotated)
> (lookup-phone-by-name "emily moore" grinnell-directory-annotated)
> (lookup-phone-by-name "Ed Moore" grinnell-directory-annotated)

For those with extra time

Extra 1: Finding people by attributes

So far, we haven’t used the last part of each entry, the attributes that someone has assigned to the person in the directory. Note that we can get those attributes by dropping the first four elements of the entry.

a. Write a recursive procedure, (lookup-last-names-by-attribute attribute dictionary), that returns a list of the last names in the entries that contain the given attribute. For example,

> (lookup-names-by-attribute "Assistant" grinnell-directory-annotated)
'("Klinge" "Osera" "Curtsinger" "Vostinar" "Rodrigues")
> (lookup-names-by-attribute "DigHum" grinnell-directory-annotated)
'("Rebelsky" "Rodrigues")
> (lookup-names-by-attribute "Annoying" grinnell-directory-annotated)
> (lookup-names-by-attribute "PM" grinnell-directory-annotated)

You may find the following procedure useful.

;;; Procedure:
;;;   list-contains?
;;; Parameters:
;;;   lst, a list
;;;   val, a value
;;; Purpose:
;;;   Determines if lst contains val.
;;; Produces:
;;;   contained?, a Boolean
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   If there is an i such that (list-ref lst i) equals val,
;;;     then contained? is true (#t).
;;;   Otherwise,
;;;     contained? is false.
(define list-contains?
  (lambda (lst val)
    (and (not (null? lst))
         (or (equal? (car lst) val)
             (list-contains? (cdr lst) val)))))

b. Suppose we wanted to find names that are both in CSC and Assistant Professors. Describe a process for doing so. Don’t write a new procedure; preferably, you should do this with a few commands in the interactions pane.

Extra 2: Searching by prefix

With assoc, we can only search the directory by complete last name. Write a procedure (lookup-by-prefix prefix directory) that searches directory for the first entry in which prefix is a prefix of the last name.

> (lookup-by-prefix "Rebel" grinnell-directory-annotated)
'("Rebelsky" "Samuel" "messy-office" "4410" "CSC" "151prof" "DigHum" "Professor")
> (lookup-by-prefix "King" grinnell-directory-annotated)
'("Kington" "Raynard" "the-prez" "3000" "Bigwig")
> (lookup-by-prefix "K" grinnell-directory-annotated)
'("Klinge" "Titus" "cauldron" "3271" "CSC" "Assistant" "151prof")
> (lookup-by-prefix "Octothorpe" grinnell-directory-annotated)


Here you will find notes on selected problems.

Notes on exercise 2

Note: The value of sidekicks is not a procedure, so it is not necessary to use a lambda-expression in this exercise. Look at the definition of grinnell-directory for an example of the form that your definition of sidekicks should take.

Return to the problem.


If we remember correctly, the table of cartoon characters and some of the related problems are due to Ben Gum.