13

我正在阅读《Land of Lisp》(顺便说一句,这是我读过的最好的技术书籍之一),我遇到了“关联列表”:

(defparameter *edges* 
  '((living-room (garden west door) 
                 (attic upstairs ladder))
    (garden (living-room east door)) 
    (attic (living-room downstairs ladder))))

Lisp 中的关联列表与 Java 的 Map(键值绑定)的概念是否相同?

对于living-room键,怎么可能有多个值?为什么要用列表括起来?

'(living-room
   ((garden west door)
    (attic upstairs ladder)))
4

4 回答 4

13
  1. 是的,关联列表是表达键值关联的一种方式。Common Lisp 为此提供的其他结构是属性列表和哈希表。

  2. 该值实际上已经包含在列表中。alist 基本上是一个对的列表,其中每对的 car 是键,而 cdr 是与该键关联的值。如果您使用 ASSOC 查找密钥 LIVING-ROOM 并将 CDR 应用于结果:

CL-USER> (cdr (assoc 'living-room *edges*))
((花园西门)(阁楼上梯子))

这背后的神奇之处在于,由于列表是由对构成的方式,因此一对其 carliving-room和其 cdr 是两个元素的列表,(garden west door)(attic upstairs ladder)可以被视为三元素列表(living-room (garden west door) (attic upstairs ladder))

通常,当将 alist 表示为带引号的对象时,您会看到用点对明确描述的元素,而不是用列表符号双关语,如下所示:

(defparameter *edges*
  '((客厅。((花园西门)
                    (阁楼上的梯子)))
    (花园。((客厅东门)))
    (阁楼。((客厅楼下的梯子)))))
于 2010-11-11T13:27:11.613 回答
6

ASSOC 返回 cons 单元格,因此包括键和值。

原因是这使得破坏性地更新值(或键)变得容易。

这里更新隐藏在 SETF 后面:

CL-USER 11 > (defparameter *edges* 
               (copy-tree
                '((living-room (garden west door) 
                               (attic upstairs ladder))
                  (garden (living-room east door)) 
                  (attic (living-room downstairs ladder)))))
*EDGES*

CL-USER 12 > (assoc 'living-room *edges*)
(LIVING-ROOM (GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))

CL-USER 13 > (cdr (assoc 'living-room *edges*))
((GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))

CL-USER 14 > (setf (cdr (assoc 'living-room *edges*)) '((garden east door)))
((GARDEN EAST DOOR))

CL-USER 15 > (cdr (assoc 'living-room *edges*))
((GARDEN EAST DOOR))
于 2010-11-11T14:34:12.810 回答
1

首先,Lisp中的关联列表和Java的Map(键值绑定)的概念是一样的吗?

Java 的 Map 是一个接口。alist 是一种使用(链接)列表存储键值对的特定方式。我不认为 Java 有任何内置 Maps 具有与 alist 相同的属性,但编写一个并不难。由于 alist 是一个列表,因此列表的所有功能和属性仍然成立。

对于客厅的钥匙,怎么可能有多个值呢?为什么不将值包含在列表中:

alist 不是 Lisp 语法的一部分。它只是一个列表,因此您可以在每个元素的 CDR 中放置您想要的任何内容。在这种情况下,它是另一个 CONS 单元格。 ASSOC只看每个元素的 CAR。

(assoc 'living-room *edges*)
(LIVING-ROOM (GARDEN WEST DOOR) (ATTIC UPSTAIRS LADDER))
于 2010-11-11T13:34:51.950 回答
1

关联列表在概念上类似于映射,因为两者都将键与值相关联。

无需在另一个列表中包含多个值,因为这会改变值的含义。我对这本书不熟悉,但似乎*EDGES*定义的方式,作者想要

(cdr (assoc 'Foobar *edges*))

成为您可以从 Foobar 获得的地点列表。正如定义的那样,如果存在单个或多个值,则为 true。

如果,当有多个值时,您将这些值嵌套在另一个列表中,那么当您想使用它们时,您只需要从该列表中挑选它们。它不会给你任何东西,它会使它与单值情况不同。

于 2010-11-11T13:34:54.177 回答