# 5.8 关联列表 Association Lists （alist）

关联列表（Association List）或简称 alist，用于记录键值对的映射。结构上时一个包含若干点对的列表，而这些点对即称为关联（associations）。每个点对的 CAR 部分称为 键（KEY），而 CDR 部分称为 关联值（associated value）。

这里有以一个关联列表的例子。key pine 和 value cones 关联；key oak 和 value acorns 关联；key maple 和 seeds 关联。

```
((pine . cones)
 (oak . acorns)
 (maple . seeds))
```

其中 keys 和 values 可以是 Lisp 中任何对象。比如，在下面的例子中，符号 a 和 数字 1 关联，字符串 “b“ 和 列表 (2 3)关联，

```
((a . 1) ("b" 2 3))
```

有时候，设计一个使用列表而非点对的关联列表来储存信息会更好。比如：

```
((rose red) (lily white) (buttercup yellow))
```

这里，我们认为 rose 作为 key 和 red 关联起来。这种关联列表的一种优点在于，你可以储存其他的相关信息——甚至是一堆其他物品组成的列表——在 CDR 的 CDR 部分中。而一个缺点是，你不可以使用 rassq（见下文）来查找包含指定值的元素。当这优缺点差不多时，这就变成了一种品味问题，不论怎样，你只要保持风格统一就好。

以上的关联列表可以被解释为元素和其CDR部分相关联；比如，key rose 和 列表 (red) 关联起来。

关联列表通常用来记录保留在堆栈里的信息。原因在于，在关联列表中在列表前方可以非常方便的添加关联。当给定一个key，在关联列表中搜寻指定关联时，将会返回第一个被找到的关联（如果有很多关联满足条件的话）。

在 Emacs Lisp 中，关联列表中出现非点对元素并不是个错误。关联列表搜寻函数将会直接忽略掉这样的元素。但很多其他版本的 lisp 可能会在这种情况下抛出异常。

请注意，属性列表和关联列表在很多方面都很相似。属性列表就像一个关联列表，不同的是，属性列表中的 key 仅仅出现一次。详情查阅 属性列表章中 属性列表和关联列表的对比部分。

Function: assoc key alist \&optional testfn\
&#x20; 这个函数返回 alist 中 第一个 key 对应的关联。它会将 key 和 关联列表中的元素的CAR部分使用 testfn 进行比较。默认情况下使用 equal 函数。如果所有大关联都不匹配，则返回nil。比如：

```
(setq trees '((pine . cones) (oak . acorns) (maple . seeds))
    => ((pine . cones) (oak . acorns) (maple . seeds))
(assoc 'oak trees)
    => (oak acrons)
(cdr (assoc 'oak trees))
    => acrons
(assoc 'birch trees)
    => nil
```

这里是另一个例子，不同的是，这里的 key 和 value 并不是符号：

```
(setq needles-per-cluster
        '((2 "Austrian Pine" "Red Pine")
          (3 "Pitch Pine")
          (5 "White Pine")))
        
(cdr (assoc 3 needles-per-cluster))
  => ("Pitch Pine")
(cdr (assoc 2 needles-per-cluster))
  => ("Austrian Pine" "Red Pine")
```

函数 assoc-string 和 assoc 很像，但这个函数忽略了一些字符意义上的不同。详情查阅 文本比较章

Function: rassoc value alist\
&#x20; 这个函数同样返回第一个和 元素的 CDR 和 value 匹配的 关联。如果没有一个关联的 CDR 和 value 匹配（equal），则返回nil。\
&#x20; rassoc  和 assoc 非常相似，不同的地方在于，assoc 取关联数组中每个关联的 car 做匹配，而 rassoc 使用每个关联的 cdr 部分。

Function: assq key alist\
&#x20; 这个函数和 assoc 很相似，不同点在于这个函数使用 eq 做比较。这个函数比 assoc 使用的更加广泛，原因在于 eq 比 equal 更快，而且大多数的关联列表都使用符号作为 key。详情查阅 谓词：相等 部分。

```
(setq trees '((pinr . cones) (oak . acorns) (maple . seeds))
    => ((pine . cones) (oak . acorns) (maple . seeds))
(assq 'pine trees)
    => (pine . cones)
```

因此这个函数不适用于不用符号作为 key 的关联列表中：

```
(setq leaves
      '(("simple leaves" . oak)
        ("compound leaves" . horsechestnut)))
        
 (assq "simple leaves" leaves)
   => Unspecified; might be nil or ("simple leaves" . oak)
 (assoc "simple leaves" leaves)
   => ("simple leaves" . oak)
```

Function: alist-get key alist \&optional default remove testfn\
&#x20; 这个函数和 assq 很相似。它
