University of California, Berkeley
EECS Department - Computer Science Division
CS3 Lecture 19 : Lists
Overview of today's lecture
Review
Tic Tac Toe project
- We saw a real project and software development up close.
- You'll be able to do that yourself soon!
Abstraction
Overview
- Abstraction is the ability to "hide"
the lower levels of detail of a system and be able to just focus
on the inputs and outputs and side-effects.
- You've used abstraction if...
- you know how to drive a car but not how a car works (down
to its very lowest detail).
- If you've used a function but didn't know how it worked (and
just trusted the description, or specification of it).
- If you've used a computer but didn't know how to build one.
Abstraction is one of the REALLY BIG IDEAS of this
course!
Lists
Overview
- We're going to motivate the need for lists by talking about
the limitations of sentences.
- Sentences can't have nested sentences or booleans in it.
E.g.,
: (define an-illegal-sentence
'(cs3 is great (but that is my (dans) opinion) and fun))
: (define another-illegal-sentence
'(#f #t #t))
- Lists can be thought of by thinking of sentences but relaxing
both those constraints...
- Lists can be created by hand, and can contain any number
of atoms
: '(yo whassup GoBears CS3isNumber 1)
==> (yo whassup gobears cs3isnumber 1
- Just as expressions can be simple or complex...
: (+ 3 5)
==> 8
: (+ 1 (/ 4 2) (+ (- 5 1) (remainder (truncate 4.9) 3)))
==> 8
- ...lists can be simple or complex too! (in fact, if you look
closely, you'll see the expression above was really a list in
itself, ooooh!). In contrast, sentences can only be simple (i.e.,
not nested).
: (define simple '(1 2 3 4) )
==> simple
: simple
==> (1 2 3 4)
: (define complex '(a (b c) ((d)) ) )
==> complex
: complex
==> (a (b c) ((d)))
- Simple is a list of four elements, the atoms 1,
2, 3 and 4
- Complex is a list of three elements, the first the
atom a, the second a list (containing two elements,
atoms b and c), and the third is a list (nested,
containing one element, which itself is a list containing d)
Data Structures
- Lists can also be used as data structures, to store
information
: (define meals
'((breakfast (3 rasberry poptarts)
(7 eggs)
(5 mango smoothies))
(lunch (2 advil)
(3 burritos)
(4 yoo-hoos))
(dinner (3 pepto-bismol)
(4 advil)
(2 nyquil)
(1 pearl milk tea))))
: meals
==> ((breakfast (3 rasberry poptarts)
(7 eggs)
(5 mango smoothies))
(lunch (2 advil)
(3 burritos)
(4 yoo-hoos))
(dinner (3 pepto-bismol)
(4 advil)
(2 nyquil)
(1 pearl milk tea)))
Selectors and Constructors Overview
- Whenever we discuss a new data type, we need to discuss the
selectors and constructors.
- The primary selectors and constructors are (you can also
find these in the back cover of the book):
- cons, list, append, car, cdr, length, null?, list?, list-ref
- We can use the variable l when using lists, just
as we used s for sentences.
Constructors
- Lists can contain no elements, this is called the
empty list (same printed representation as the empty
sentence)
: '()
==> ()
- They can be created explicitly as we have seen so
far
: '(this is a list)
==> (this is a list)s
- ...or they can be created through constructors, as
in
- (cons element list)
- Returnslist with element
inserted at the start
- (append list1 list2 ... listn)
- Returns the list formed by concatenating the elements of
list1 ... listn
- (list el1 el2 ... eln)
- returns the list (el1 el2 ... eln)
- Examples:
: (cons 'cs3 '())
==> (cs3)
: (car '(cs3))
==> cs3
: (cdr '(cs3))
==> ()
: (cons 'love (cons 'cs3 '()))
==> (love cs3)
: (cons 'i (cons 'love (cons 'cs3 '())))
==> (1 love cs3)
: (cons '(1 2) '(3 4))
==> ((1 2) 3 4)
: (list 1 2 5 'three-sir 3)
==> (1 2 5 three-sir 3)
: (list 1 2 5 '(3 sir) 3)
==> (1 2 5 (3 sir) 3)
: (append '(1) '(2 (3)) '() '(4 5 6) '(((7))) )
==> (1 2 (3) 4 5 6 ((7)))
- Ways you can think about it:
- cons stuffs its first argument into the paren of
the second
- list just dissolves the word list
- append dissolves parenthesis around each element
- And, taken together, these are the CAL
functions (Cons Append List)!
Selectors
- The primary selecttors are car and cdr:
- (car list)
- same as first, but for lists - i.e., return the
first element of the list, if there is one.
- (cdr list)
- same as butfirst (pronounced "could-er"),
but for lists - i.e., return all but the first element of the
list.
: (define my-list
'(cs3 is great (but that is my (dans) opinion) and fun))
: my-list
==> (cs3 is great (but that is my (dans) opinion) and fun)
: (car my-list)
==> cs3
: (cdr my-list)
==> (is great (but that is my (dans) opinion) and fun)
: (cdr (cdr my-list))
==> (great (but that is my (dans) opinion) and fun)
: (cdr (cdr (cdr my-list)))
==> ((but that is my (dans) opinion) and fun)
: (cdr (cdr (cdr (cdr my-list))))
==> (and fun)
- It is an error to request the car or cdr
of an empty list:
: (car '())
*** ERROR -- PAIR expected
(car '())
: (cdr '())
*** ERROR -- PAIR expected
(cdr '())
- There are also built-in shortcuts which allow you to combine
several (up to 4) consecutive cars and cdrs
together:
: my-list
==> (cs3 is great (but that is my (dans) opinion) and fun)
: (car (cdr (cdr (cdr my-list))))
==> (but that is my (dans) opinion)
: (cadddr my-list)
==> (but that is my (dans) opinion
Programming with Lists
- Here are some recursive programs with nested lists
: (define (are-you-a-list l)
(if (null? l) '()
(cons (list? (car l))
(are-you-a-list (cdr l)))))
: (are-you-a-list '(a (b c) () ((d))) )
==> (#f #t #t #t)
- Note what happens when I change cons to list:
: (define (are-you-a-list-broken l)
(if (null? l) '()
(list (list? (car l))
(are-you-a-list-broken (cdr l)))))
: (are-you-a-list-broken '(a (b c) () ((d))) )
==> (#f (#t (#t (#t ()))))
The Truth about Sentences
- They're really a simplification of lists! (and soylent green
is made of people!)
- We "watered-down" lists and added constructs from
the logo (butfirst, etc) programming language when we
first taught you sentences.
Higher-Order Functions
- There are three primary higher-order functions similar to
the sentence HOFs which operate on the top-level elements of
lists:
- map (similar to every)
- filter (similar to keep)
- reduce (similar to accumulate)
- Examples:
: (define (are-you-a-list-hof l)
(map list? l))
: (are-you-a-list-hof '(a (b c) () ((d))) )
==> (#f #t #t #t)
- We couldn't have done this with sentences for two reasons:
- Sentences can't have nested lists
- The returned list cannot be a sentence because it has booleans
in it.
- Filter all the lists and non-lists.
: (filter list? '(a (b c) () ((d))) )
==> ((b c) () ((d)))
: (filter word? '(a (b c) () ((d))) )
==> (a)
- Return the longest sublist...
: (reduce (lambda (x y)
(if (> (length x) (length y)) x y))
'(a (b c) () ((d))) )
==> (b c)
Other Primitives for Lists: length,
null?, list?, list-ref, equal?, member
length
- Lists also have length which we can query (much like
the count of a sentence)
- (length list)
- returns the number of top-level elements in list
(ala count)
: (length '(1 2 3 4) )
==> 4
: (length '(a (b c) () ((d))) )
==> 4
: (length '())
==> 0
null?
- When recursing, one often has to test for the null list using
the predicate null?
- (null? list)
- returns #t iff list is null, otherwise
#f. (ala empty? for sentences)
: (null? '(1 2 3 4) )
==> #f
: (null? '() )
==> #t
list?
- When you've been given something and are wondering whether
it is a list...
- returns #t iff list is a list, otherwise
#f. (ala sentence? for sentences)
: (list? '(1 2 3 4) )
==> #t
: (list? '() )
==> #t
: (list? 'cs3 )
==> #f
list-ref
- list-ref is like item (for sentences)
- (list-ref list position)
- returns the 0-origin (i.e., starting from 0) element from
list specified by position.
: (list-ref '(a b c d) 1)
==> b
: (list-ref '(a b c d) 5)
*** ERROR -- PAIR expected
(list-ref '(a b c d) 5)
: (list-ref '(a (b c) () ((d))) 3)
==> ((d))
: (list-ref '() 0)
*** ERROR -- PAIR expected
(list-ref '(a b c d) 5)
equal?
- equal? works for lists also, and
- (equal? list1 list2)
- returns #t if two lists have the same printed representation.
: (equal? '(a (b c) () ((d))) (a (b c) () ((d))) )
==> #t
member
- member is like member? (for sentences),
except it's a semi-predicate
- (member element list)
- seaches through the top-level elements of list,
and when it finds element, returns the part of list
starting with element. If it don't find it, it
returns #f.
: (member '(b c) '(a (b c) () ((d))) )
==> ((b c) () ((d)))
: (member 'a-new-word '(a (b c) () ((d))) )
==> #f
Association Lists
- An association list is a data structure built on lists.
- The idea is to have a list of keys and data: ((key1 data2)
(key2 data2) ...)
- (assoc key association-list)
- Find the key in the key-data pairs
and return the sublist whose key matches. If
no match is found, return #f.
: (define my-a-list '((dan garcia) (george bush) (bill clinton) (bill cosby)))
: (assoc 'dan my-a-list)
==> (dan garcia)
: (assoc 'bill my-a-list)
==> (bill clinton)
: (assoc 'raoul my-a-list)
==> #f
Recursion on Arbitrary Structured Lists
- This can be confusing, do lots of examples to study.
- We start by writing add-1-to-all, then modify it
to go deep.
- All the higher-order functions (map, filter, reduce)
only work on the top-level, they do not go deep.
;; deep-add-1
;;
;; INPUTS : A deep list of numbers
;; REQUIRES : There be nothing but numbers (and lists of #s) in the list.
;; SIDE-EFFECTS : None
;; RETURNS : The original list with every number incremented by 1.
;; EXAMPLE : (deep-add-1 '(1 5 2) ) ==> (2 6 3)
;; : (deep-add-1 '((1 2 (3 4 5) 6) 7 (((8)))) )
;; : ==> ((2 3 (4 5 6) 7) 8 (((9))))
: (define (deep-add-1 l)
(cond ((null? l) '())
((number? l) (+ l 1))
(else (cons (deep-add-1 (car l))
(deep-add-1 (cdr l))))))
: (deep-add-1 '(1 (2 ((4)) 3) (5)) )
==> (2 (3 ((5)) 4) (6))
Summary
- Whew! There was a LOT to cover in one lecture -- in retrospect,
two lectures, probably.
Next Time
- We'll look at another data structure, trees.
Puzzle : Unmarked Clock [courtesy Yeh-Kai
Tung (yktung@physics.Berkeley.EDU)]
- You are given a clock with the numbers removed and all but
one of the number markers also removed, leaving the minute and
hour hands and one of the hour markers (but you don't know which
one).
- The clock is circular, so you can't tell the original orientation
of it.
- With just a protractor and your logic, your goal is to determine
the exact time and original positions and numbering of the other
12 dots:
- Easy: in 12 hours (i.e., sometime in a 12-hour period, give
an answer)
- Medium: in 1 hour and 10 minutes
- Hard: instantaneously
Game : Dots and Boxes ["Pentagames"
by Pentagram, Fireside Publishing, 1990]
- Using squared or plain paper, mark out ten rows of ten dots.
- Two players take it in turn to draw a straight line connecting
any two adjacent dots, either horizontally or vertically.
- The object of the game is to make the fourth line of any
square and claim it, marking it with your initial.
- When all the dots have been joined, the player with the most
boxes is the winner.
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |
o |