当键是字符串时,我可以使用assoc吗?

joh*_*ers 7 lisp common-lisp

我有这样的数据集: '(("red" 3 5)("blue" 6 8)...)

assoc当键是字符串时是否可以使用?在这个简单的测试中,没有一个明显的尝试对我有用:

CL-USER> (defparameter ggg (list '("foot" 2) '(bar 5)))
GGG
CL-USER> ggg
(("foot" 2) (BAR 5))
CL-USER> (assoc 'bar ggg)
(BAR 5)
CL-USER> (assoc "foot" ggg)
NIL
CL-USER> (assoc '"foot" ggg)
NIL
CL-USER> (assoc 'foot ggg)
NIL
Run Code Online (Sandbox Code Playgroud)

Kaz*_*Kaz 9

如果您确定列表仅包含字符串,则可以使用特定于类型的函数string=(区分大小写)或string-equal(不区分大小写).

但是,这些函数也接受符号,符号和字符串的混合.

因此,(assoc "ABC" list :test #'string=)不仅会找到密钥,还会找到"ABC"名称所在的任何符号"ABC",例如符号:abccl-use:abcmypackage:abc.

用于比较任何两个对象的泛型equalequalp函数没有此行为.与前面提到的两个一样,equal并且equalp分别是区分大小写和不敏感的.但是,它们也比较了其他类型的对象.

string=和不同string-equal,equal并且equalp不认为字符串和符号是等价的; 就是,(equalp "FOO" 'FOO) -> nil.他们也不认为具有相同名称的符号是等效的:(equalp 'foo :foo) -> nil.当两个参数是符号,equalequalp采用同样的测试的eq功能.

所以,我认为,你的关联列表中选择合适的测试,因为你有串和符号键的混合物,是两个功能之一equalequalp.

这些功能还允许您的列表具有其他类型的键,如数字.equalp将按值比较数字,以便1和1.0是相同的键,而equal更紧.这两个函数都会递归到列表中.名单(1 2)(1 2)equal即使它们不是同一个对象(单独consed),而(1 2)(1 2.0)没有equal,但equalp(除非你有一个非常奇怪的浮点系统).另外,矢量对象不是按元素逐个比较的equal,而是它们的比较equalp.

即使你只在列表中有字符串,使用这两个函数仍然更好.您不会获得太多(如果有的话)性能优势.string=仍然必须验证参数的类型以确保它们是受支持的类型,并根据参数的字符串和符号的组合进行调度.equal根据众多类型的可能性进行调度,但这可以有效地完成.

在Lisp中使用过度类型特定的函数或不恰当的严格平等作为习惯问题是一种糟糕的做法.

string=但是,故意使用,不是为了节省机器周期,而是在必须将符号作为字符串或符号和字符串的混合进行比较的情况下.例如,如果您正在实现loop宏,则可以使用它string=来检测loop子句单词,根据ANSI Common Lisp规范,它根据符号名称被视为等效.用户可以写(loop :for x below 42 ...)(loop mypackage:for x below 42 ...).但是(loop "FOR" ...)无效!所以你不能依靠string=; 你必须验证子句是一个符号.


Bar*_*mar 6

(assoc "foot" ggg :test #'string-equal)
Run Code Online (Sandbox Code Playgroud)

要么

(assoc "foot" ggg :test #'string=)
Run Code Online (Sandbox Code Playgroud)

取决于您是否希望比较区分大小写.