211 lines
10 KiB
HTML
211 lines
10 KiB
HTML
![]() |
<!DOCTYPE HTML PUBLIC "-//W3O//DTD W3 HTML 2.0//EN">
|
||
|
<!Converted with LaTeX2HTML 0.6.5 (Tue Nov 15 1994) by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds >
|
||
|
<HEAD>
|
||
|
<TITLE>15.6. Association Lists</TITLE>
|
||
|
</HEAD>
|
||
|
<BODY>
|
||
|
<meta name="description" value=" Association Lists">
|
||
|
<meta name="keywords" value="clm">
|
||
|
<meta name="resource-type" value="document">
|
||
|
<meta name="distribution" value="global">
|
||
|
<P>
|
||
|
<b>Common Lisp the Language, 2nd Edition</b>
|
||
|
<BR> <HR><A NAME=tex2html3435 HREF="node154.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html3433 HREF="node147.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html3429 HREF="node152.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html3437 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html3438 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
|
||
|
<B> Next:</B> <A NAME=tex2html3436 HREF="node154.html"> Hash Tables</A>
|
||
|
<B>Up:</B> <A NAME=tex2html3434 HREF="node147.html"> Lists</A>
|
||
|
<B> Previous:</B> <A NAME=tex2html3430 HREF="node152.html"> Using Lists as </A>
|
||
|
<HR> <P>
|
||
|
<H1><A NAME=SECTION001960000000000000000>15.6. Association Lists</A></H1>
|
||
|
<P>
|
||
|
An <i>association list</i>, or <i>a-list</i>, is a data structure
|
||
|
used very frequently in Lisp. An a-list is a list of pairs (conses);
|
||
|
each pair is an association. The <i>car</i> of a pair is called the <i>key</i>,
|
||
|
and the <i>cdr</i> is called the <i>datum</i>.
|
||
|
<P>
|
||
|
An advantage of the a-list representation is that an a-list can be
|
||
|
incrementally augmented simply by adding new entries to the front.
|
||
|
Moreover, because the searching function <tt>assoc</tt> searches the
|
||
|
a-list in order, new entries can ``shadow'' old entries. If an a-list is
|
||
|
viewed as a mapping from keys to data, then the mapping can be not only
|
||
|
augmented but also altered in a non-destructive manner by adding new
|
||
|
entries to the front of the a-list.
|
||
|
<P>
|
||
|
Sometimes an a-list represents a bijective mapping, and it is desirable
|
||
|
to retrieve a key given a datum. For this purpose, the ``reverse'' searching
|
||
|
function <tt>rassoc</tt> is provided. Other variants of a-list searches
|
||
|
can be constructed using the function <tt>find</tt> or <tt>member</tt>.
|
||
|
<P>
|
||
|
It is permissible to let <tt>nil</tt> be an element of an a-list in place of
|
||
|
a pair. Such an element is not considered to be a pair but is simply
|
||
|
passed over when the a-list is searched by <tt>assoc</tt>.
|
||
|
<P>
|
||
|
<BR><b>[Function]</b><BR>
|
||
|
<tt>acons <i>key</i> <i>datum</i> <i>a-list</i></tt><P><tt>acons</tt> constructs a new association list by adding the pair
|
||
|
<tt>(<i>key</i> . <i>datum</i>)</tt> to the old <i>a-list</i>.
|
||
|
<P><pre>
|
||
|
(acons x y a) == (cons (cons x y) a)
|
||
|
</pre><P>
|
||
|
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
|
||
|
This is a trivial convenience function, but I find I use it a lot.
|
||
|
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
|
||
|
<P>
|
||
|
<BR><b>[Function]</b><BR>
|
||
|
<tt>pairlis <i>keys</i> <i>data</i> &optional <i>a-list</i></tt><P><tt>pairlis</tt> takes two lists and makes an association list that associates
|
||
|
elements of the first list to corresponding elements of the second
|
||
|
list. It is an error if the two lists <i>keys</i> and <i>data</i> are not of
|
||
|
the same length. If the optional argument <i>a-list</i> is provided, then the
|
||
|
new pairs are added to the front of it.
|
||
|
<P>
|
||
|
The new pairs may appear in the resulting a-list in any order;
|
||
|
in particular, either forward or backward order is permitted.
|
||
|
Therefore the result of the call
|
||
|
<P><pre>
|
||
|
(pairlis '(one two) '(1 2) '((three . 3) (four . 19)))
|
||
|
</pre><P>
|
||
|
might be
|
||
|
<P><pre>
|
||
|
((one . 1) (two . 2) (three . 3) (four . 19))
|
||
|
</pre><P>
|
||
|
but could equally well be
|
||
|
<P><pre>
|
||
|
((two . 2) (one . 1) (three . 3) (four . 19))
|
||
|
</pre><P>
|
||
|
<P>
|
||
|
<BR><b>[Function]</b><BR>
|
||
|
<tt>assoc <i>item</i> <i>a-list</i> &key :test :test-not :key <BR></tt><tt>assoc-if <i>predicate</i> <i>a-list</i> <BR></tt><tt>assoc-if-not <i>predicate</i> <i>a-list</i></tt><P>
|
||
|
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
|
||
|
X3J13 voted in March 1988
|
||
|
(ASSOC-RASSOC-IF-KEY) <A NAME=17126> </A>
|
||
|
to allow <tt>assoc-if</tt> and <tt>assoc-if-not</tt>
|
||
|
also to take a keyword argument named <tt>:key</tt>, to be used
|
||
|
to determine whether a pair ``satisfies the test'' in the same manner as
|
||
|
for sequence functions. The new function descriptions are therefore as follows:
|
||
|
<P>
|
||
|
<BR><b>[Function]</b><BR>
|
||
|
<tt>assoc-if <i>predicate</i> <i>a-list</i> &key :key <BR></tt><tt>assoc-if-not <i>predicate</i> <i>a-list</i> &key :key</tt><P>
|
||
|
The omission of <tt>:key</tt> arguments for these
|
||
|
functions in the first edition was probably an oversight.
|
||
|
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
|
||
|
<P>
|
||
|
Each of these searches the association list
|
||
|
<i>a-list</i>. The value is the first pair in the a-list such that
|
||
|
the <i>car</i> of the pair satisfies the test, or <tt>nil</tt> if there is
|
||
|
no such pair in the a-list.
|
||
|
For example:
|
||
|
<P><pre>
|
||
|
(assoc 'r '((a . b) (c . d) (r . x) (s . y) (r . z)))
|
||
|
=> (r . x)
|
||
|
(assoc 'goo '((foo . bar) (zoo . goo))) => <tt>nil</tt>
|
||
|
(assoc '2 '((1 a b c) (2 b c d) (-7 x y z))) => (2 b c d)
|
||
|
</pre><P>
|
||
|
It is possible to <tt>rplacd</tt> the result of <tt>assoc</tt> <i>provided</i>
|
||
|
that it is not <tt>nil</tt>,
|
||
|
in order to ``update'' the ``table'' that was <tt>assoc</tt>'s second argument.
|
||
|
(However, it is often better to update an a-list by adding new pairs
|
||
|
to the front, rather than altering old pairs.)
|
||
|
For example:
|
||
|
<P><pre>
|
||
|
(setq values '((x . 100) (y . 200) (z . 50)))
|
||
|
(assoc 'y values) => (y . 200)
|
||
|
(rplacd (assoc 'y values) 201)
|
||
|
(assoc 'y values) => (y . 201) now
|
||
|
</pre><P>
|
||
|
A typical trick is to say
|
||
|
<tt>(cdr (assoc x y))</tt>.
|
||
|
Because the <i>cdr</i> of <tt>nil</tt> is guaranteed to be <tt>nil</tt>,
|
||
|
this yields <tt>nil</tt> if no pair is found <i>or</i> if a pair is
|
||
|
found whose <i>cdr</i> is <tt>nil</tt>. This is useful if <tt>nil</tt> serves
|
||
|
its usual role as a ``default value.''
|
||
|
<P>
|
||
|
The two expressions
|
||
|
<P><pre>
|
||
|
(assoc <i>item</i> <i>list</i> :test <i>fn</i>)
|
||
|
</pre><P>
|
||
|
and
|
||
|
<P><pre>
|
||
|
(find <i>item</i> <i>list</i> :test <i>fn</i> :key #'car)
|
||
|
</pre><P>
|
||
|
are equivalent in meaning with one important exception:
|
||
|
if <tt>nil</tt> appears in the a-list in place of a pair,
|
||
|
and the <i>item</i> being searched for is <tt>nil</tt>,
|
||
|
<tt>find</tt> will blithely compute the <i>car</i> of the <tt>nil</tt> in the a-list,
|
||
|
find that it is equal to the <i>item</i>, and return <tt>nil</tt>,
|
||
|
whereas <tt>assoc</tt> will ignore the <tt>nil</tt> in the a-list and continue
|
||
|
to search for an actual pair (cons) whose <i>car</i> is <tt>nil</tt>.
|
||
|
See <tt>find</tt> and <tt>position</tt>.
|
||
|
<P>
|
||
|
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
|
||
|
X3J13 voted in January 1989
|
||
|
(MAPPING-DESTRUCTIVE-INTERACTION) <A NAME=17182> </A>
|
||
|
to restrict user side effects; see section <A HREF="node92.html#STRUCTURETRAVERSALSECTION">7.9</A>.
|
||
|
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
|
||
|
<P>
|
||
|
<hr>
|
||
|
<b>Compatibility note:</b> In MacLisp, the <tt>assoc</tt> function uses
|
||
|
an <tt>equal</tt> comparison rather than <tt>eql</tt>, which is the default
|
||
|
test for <tt>assoc</tt> in Common Lisp. Where in MacLisp one would write
|
||
|
<tt>(assoc x y)</tt>, in Common Lisp one must write <tt>(assoc x y :test #'equal)</tt>
|
||
|
to get the completely identical effect. Similarly, one can get the
|
||
|
precise effect, and no more, of the MacLisp <tt>(assq x y)</tt>
|
||
|
by writing in Common Lisp <tt>(assoc x y :test #'eq)</tt>.
|
||
|
<hr>
|
||
|
<P>
|
||
|
In Interlisp, <tt>assoc</tt> uses an <tt>eq</tt> test, and <tt>sassoc</tt>
|
||
|
uses an Interlisp <tt>equal</tt> test.
|
||
|
<P>
|
||
|
<BR><b>[Function]</b><BR>
|
||
|
<tt>rassoc <i>item</i> <i>a-list</i> &key :test :test-not :key <BR></tt><tt>rassoc-if <i>predicate</i> <i>a-list</i> <BR></tt><tt>rassoc-if-not <i>predicate</i> <i>a-list</i></tt><P>
|
||
|
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
|
||
|
X3J13 voted in March 1988
|
||
|
(ASSOC-RASSOC-IF-KEY) <A NAME=17202> </A>
|
||
|
to allow <tt>rassoc-if</tt> and <tt>rassoc-if-not</tt>
|
||
|
also to take a keyword argument named <tt>:key</tt>, to be used
|
||
|
to determine whether a pair ``satisfies the test'' in the same manner as
|
||
|
for sequence functions. The new function descriptions are therefore as follows:
|
||
|
<P>
|
||
|
<BR><b>[Function]</b><BR>
|
||
|
<tt>rassoc-if <i>predicate</i> <i>a-list</i> &key :key <BR></tt><tt>rassoc-if-not <i>predicate</i> <i>a-list</i> &key :key</tt><P>
|
||
|
The omission of <tt>:key</tt> arguments for these
|
||
|
functions in the first edition was probably an oversight.
|
||
|
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
|
||
|
<P>
|
||
|
<tt>rassoc</tt> is the reverse form of <tt>assoc</tt>; it searches for
|
||
|
a pair whose <i>cdr</i> satisfies the test, rather than the <i>car</i>.
|
||
|
If the <i>a-list</i> is considered to be a mapping, then <tt>rassoc</tt>
|
||
|
treats the <i>a-list</i> as representing the inverse mapping.
|
||
|
For example:
|
||
|
<P><pre>
|
||
|
(rassoc 'a '((a . b) (b . c) (c . a) (z . a))) => (c . a)
|
||
|
</pre><P>
|
||
|
<P>
|
||
|
The expressions
|
||
|
<P><pre>
|
||
|
(rassoc <i>item</i> <i>list</i> :test <i>fn</i>)
|
||
|
</pre><P>
|
||
|
and
|
||
|
<P><pre>
|
||
|
(find <i>item</i> <i>list</i> :test <i>fn</i> :key #'cdr)
|
||
|
</pre><P>
|
||
|
are equivalent in meaning, except when the <i>item</i> is <tt>nil</tt>
|
||
|
and <tt>nil</tt> appears in place of a pair in the a-list. See the discussion
|
||
|
of the function <tt>assoc</tt>.
|
||
|
<P>
|
||
|
<img align=bottom alt="change_begin" src="gif/change_begin.gif"><br>
|
||
|
X3J13 voted in January 1989
|
||
|
(MAPPING-DESTRUCTIVE-INTERACTION) <A NAME=17234> </A>
|
||
|
to restrict user side effects; see section <A HREF="node92.html#STRUCTURETRAVERSALSECTION">7.9</A>.
|
||
|
<br><img align=bottom alt="change_end" src="gif/change_end.gif">
|
||
|
<P>
|
||
|
|
||
|
<P>
|
||
|
<BR> <HR><A NAME=tex2html3435 HREF="node154.html"><IMG ALIGN=BOTTOM ALT="next" SRC="icons/next_motif.gif"></A> <A NAME=tex2html3433 HREF="node147.html"><IMG ALIGN=BOTTOM ALT="up" SRC="icons/up_motif.gif"></A> <A NAME=tex2html3429 HREF="node152.html"><IMG ALIGN=BOTTOM ALT="previous" SRC="icons/previous_motif.gif"></A> <A NAME=tex2html3437 HREF="node1.html"><IMG ALIGN=BOTTOM ALT="contents" SRC="icons/contents_motif.gif"></A> <A NAME=tex2html3438 HREF="index.html"><IMG ALIGN=BOTTOM ALT="index" SRC="icons/index_motif.gif"></A> <BR>
|
||
|
<B> Next:</B> <A NAME=tex2html3436 HREF="node154.html"> Hash Tables</A>
|
||
|
<B>Up:</B> <A NAME=tex2html3434 HREF="node147.html"> Lists</A>
|
||
|
<B> Previous:</B> <A NAME=tex2html3430 HREF="node152.html"> Using Lists as </A>
|
||
|
<HR> <P>
|
||
|
<HR>
|
||
|
<P><ADDRESS>
|
||
|
AI.Repository@cs.cmu.edu
|
||
|
</ADDRESS>
|
||
|
</BODY>
|