# 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 很相似。它


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://emacs-lisp.ivory.cafe/lie-biao/guan-xi-lie-biao-association-lists-alist.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
