#lang racket (require csc151) ;;; File: ;;; association-lists-lab.rkt ;;; Authors: ;;; Titus Klinge ;;; Samuel A. Rebelsky ;;; YOUR NAME HERE ;;; Summary: ;;; Data and procedures for the lab on association lists. ;;; Values: ;;; grinnell-directory ;;; grinnell-directory-annotated ;;; Type: ;;; List of lists. ;;; Note: ;;; * Each sublist is of length at least four and contains a last ;;; name, a first name, a username, a phone number, and an ;;; optional sequence of annotations. ;;; * The ;;; Contents: ;;; A list of people at Grinnell with contact information and some ;;; useful attributes. (define grinnell-directory (list (list "Rebelsky" "Samuel" "messy-office" "4410") (list "Klinge" "Titus" "cauldron" "3271") (list "Weinman" "Jerod" "map-reader" "9812") (list "Osera" "PM" "type-snob" "4010") (list "Curtsinger" "Charlie" "systems-guy" "3127") (list "Vostinar" "Anya" "cache" "4306") (list "Dahlby-Albright" "Sarah" "cheery-coach" "4362") (list "Rodrigues" "Liz" "vivero" "3362") (list "Barks" "Sarah" "stem-careers" "4940") (list "Kington" "Raynard" "the-prez" "3000"))) (define grinnell-directory-annotated (list (list "Rebelsky" "Samuel" "messy-office" "4410" "CSC" "151prof" "DigHum" "Professor") (list "Klinge" "Titus" "cauldron" "3271" "CSC" "Assistant" "151prof") (list "Weinman" "Jerod" "map-reader" "9812" "CSC" "Chair" "Associate" "NSF Grant") (list "Osera" "PM" "type-snob" "4010" "Assistant" "NSF Grant" "Tutorial" "CSC") (list "Curtsinger" "Charlie" "systems-guy" "3127" "CSC" "Assistant" "Tutorial" "ASFAC") (list "Vostinar" "Anya" "cache" "4306" "CSC" "Assistant" "Interdisciplinary") (list "Dahlby-Albright" "Sarah" "cheery-coach" "4362" "Statistics" "CSC" "Outreach") (list "Rodrigues" "Liz" "vivero" "3362" "LIB" "DigHum" "Assistant" ) (list "Barks" "Sarah" "stem-careers" "4940" "CLS" "STEM" "Neuroscience") (list "Kington" "Raynard" "the-prez" "3000" "Bigwig"))) ;;; Procedure: ;;; lookup-email-by-last-name ;;; Parameters: ;;; last-name, a string ;;; directory, a list of directory entries ;;; Purpose: ;;; Look up an email address in the table. ;;; Produces: ;;; email-address, a string ;;; Preconditions: ;;; * Each entry in directory must be a list. ;;; * Element 0 of each entry must be a string which represents the ;;; last name. ;;; * Element 2 of each entry must be a string which represents the ;;; user name. ;;; * Email addresses have the form "username@grinnell.edu". ;;; Postconditions: ;;; * If an entry for the last name appears once in the table, ;;; email-address represents their email address. ;;; * If multiple entries with a matching last name appear in the table, ;;; email-address represents the email address for one of them. ;;; * If no entries with a matching last name appear in the table, ;;; email-address is the empty string, "" ;;; * Does not affect the table. (define lookup-email-by-last-name (lambda (last-name directory) (let ([assoc-result (assoc last-name directory)]) (if assoc-result (string-append (list-ref assoc-result 2) "@grinnell.edu") "")))) ;;; Procedure: ;;; lookup-person-by-phone ;;; Parameters: ;;; phone, a string ;;; directory, a list of directory entries ;;; Purpose: ;;; Find the name of the person who has a particular phone number. ;;; Produces: ;;; name, a string (or the value #f) ;;; Preconditions: ;;; * phone is a string with four digits. ;;; * Each entry in directory must be a list. ;;; * Element 0 of each entry must be a string which represents the ;;; last name. ;;; * Element 1 of each entry must be a string which represents the ;;; first name. ;;; * Element 3 of each entry must be a string which represents the ;;; four-digit phone number. ;;; * People have both first names and last names. ;;; Postconditions: ;;; * If an entry for the phone number appears once in the table, ;;; name represents their name. ;;; * If multiple entries with a matching phone number appear in the ;;; table, name represents the name for one of them. ;;; * If no entries with a matching phone number appear in the table, ;;; name is #f. ;;; * Does not affect the table. (define lookup-person-by-phone (lambda (phone directory) (cond [(null? directory) #f] [(equal? phone (list-ref (car directory) 3)) (string-append (cadar directory) " " (caar directory))] [else (lookup-person-by-phone phone (cdr directory))]))) (define assoc-ci (lambda (key alist) (cond ; If there are no entries left in the association list, ; there are no entries with the given key. [(null? alist) #f] ; If the key we're looking for is the key of the first ; entry, then use that entry. [(string-ci=? key (car (car alist))) (car alist)] ; Otherwise, look in the rest of the association list. [else (assoc-ci key (cdr alist))]))) (define assoc-new (let ([match? (lambda (val1 val2) (or (and (string? val1) (string? val2) (string-ci=? val1 val2)) (equal? val1 val2)))]) (lambda (key alist) (cond ; If there are no entries left in the association list, ; there are no entries with the given key. [(null? alist) #f] ; If the key we're looking for matches the key of the first ; entry, then use that entry. [(match? key (car (car alist))) (car alist)] ; Otherwise, look in the rest of the association list. [else (assoc-new key (cdr alist))])))) ;;; lookup-name-by ;;; Parameters: ;;; key, a string ;;; position, an integer between 0 and 3, inclusive ;;; directory, a list of directory entries ;;; Purpose: ;;; Find the full name of a person who has a matching string at ;;; the designated position (0 for last name, 1 for first name, ;;; 2 for username, and 3 for four-digit phone number). ;;; Produces: ;;; name, a string (or the value #f) ;;; Preconditions: ;;; * phone is a string with four digits. ;;; * Each entry in directory must be a list. ;;; * Element 0 of each entry must be a string which represents the ;;; last name. ;;; * Element 1 of each entry must be a string which represents the ;;; first name. ;;; * Element 2 of each entry must be a string which represents the ;;; user name. ;;; * Element 3 of each entry must be a string which represents the ;;; four-digit phone number. ;;; * People have both first names and last names. ;;; Postconditions: ;;; If position is 0 and an entry with the same last name appears ;;; somewhere in the table, name is the name associated with ;;; one such entry. ;;; If position is 1 and an entry with the same first name appears ;;; somewhere in the table, name is the name associated with ;;; one such entry. ;;; If position is 2 and an entry with the same user name appears ;;; somewhere in the table, name is the name associated with ;;; one such entry. ;;; If position is 3 and an entry with the same four-digit phone ;;; appears somewhere in the table, name is the name associated ;;; with one such entry. ;;; If no matching entries appear, cname is #f. ;;; Does not affect the table. (define lookup-name-by (lambda (key position directory) (cond [(null? directory) #f] [(string-ci=? key (list-ref (car directory) position)) (string-append (cadar directory) " " (caar directory))] [else (lookup-name-by key position (cdr directory))]))) ; Look up a name by username (define lookup-name-by-username (lambda (uname directory) (lookup-name-by uname 2 directory))) ; Look up a name by first name (define lookup-name-by-first-name (section lookup-name-by <> 1 <>))