协会名单
普通列表对于表示元素序列很有用,但有时表示一种键值映射更有帮助。Common Lisp 提供了几种方法,包括真正的哈希表(参见 18.1 哈希表概念 )。在 Common Lisp 中有两种主要方式或表示值映射的键: 属性列表和关联列表 。此示例描述了关联列表。
关联列表或 alist 是普通列表,其元素是点对,其中每对的汽车是密钥,并且每对的 cdr 是关联值。例如,
(defparameter *ages* (list (cons 'john 34) (cons 'mary 23) (cons 'tim 72)))
可以被认为是将表示个人姓名的符号与表示年龄的整数映射的关联列表。可以使用简单列表函数(如 member) 实现一些检索功能。例如,要检索约翰的年龄,可以写
(cdr (first (member 'mary *age* :key 'car)))
;=> 23
所述构件函数返回与一个 cons 单元,其在开始列表的尾部车是玛丽,即, ((玛丽 23)(TIM。72)) ,第一返回列表中,这是第一个元素 (玛丽。23) , cdr 返回该对的右侧,即 23 。虽然这是访问关联列表中的值的一种方法,但是像关联列表这样的约定的目的是从底层表示(列表)中抽象出来并提供用于处理数据结构的更高级函数。
对于关联列表,检索功能是 assoc ,它接受密钥,关联列表和可选的测试关键字(key,test,test-not),并返回对应密钥的对:
(assoc 'tim *ages*)
;=> (tim . 72)
由于如果项目存在,结果将始终为 cons 单元格,如果 assoc 返回 nil ,则该项目不在列表中:
(assoc 'bob *ages*)
;=> nil
为了更新关联列表中的值, setf 可以与 cdr 一起使用。例如,当约翰的生日到来并且他的年龄增加时,可以执行以下任一操作:
(setf (cdr (assoc 'john *ages*) 35)
(incf (cdr (assoc 'john *ages*)))
incf 适用于这种情况,因为它基于 setf 。
关联列表也可以用作一种双向映射,因为通过使用反向关联函数 rassoc ,可以根据值检索关键值映射。
在此示例中,关联列表是通过显式使用 list 和 cons 创建的,但也可以使用 pairlis 创建关联列表, pairlis 获取键和数据列表并基于它们创建关联列表:
(pairlis '(john mary tim) '(23 67 82))
;=> ((john . 23) (mary . 67) (tim . 82))
可以使用 acons 将单个键和值对添加到关联列表 :
(acons 'john 23 '((mary . 67) (tim . 82)))
;=> ((john . 23) (mary . 67) (tim . 82))
ASSOC 功能通过列表搜索从左至右,这意味着是能够不从列表中去除它们或更新的任何列表中的结构中的关联列表掩模的值,仅仅通过添加新元素添加到列表的开头。该 acons 功能提供了这一点:
(defvar *ages* (pairlis '(john mary tim) '(34 23 72)))
(defvar *new-ages* (acons 'mary 29 *ages*))
*new-ages*
;=> ((mary . 29) (john . 34) (mary . 23) (tim . 72))
现在,对 mary 的查找将返回第一个条目:
(assoc 'mary *new-ages*)
;=> 29