emacs.d/clones/lisp/www.cs.cmu.edu/Groups/AI/html/cltl/clm/node153.html

211 lines
10 KiB
HTML
Raw Normal View History

2022-08-26 19:11:35 +02:00
<!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> &amp;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> &amp;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>&#160;</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> &amp;key :key <BR></tt><tt>assoc-if-not <i>predicate</i> <i>a-list</i> &amp;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>&#160;</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> &amp;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>&#160;</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> &amp;key :key <BR></tt><tt>rassoc-if-not <i>predicate</i> <i>a-list</i> &amp;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>&#160;</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>