協會名單
普通列表對於表示元素序列很有用,但有時表示一種鍵值對映更有幫助。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