Могу ли я использовать assoc, когда ключи являются строками?

у меня есть такой набор данных:'(("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

4 ответов


если вы уверены, что ваш список содержит только строки, вы можете использовать тип функции string= (с учетом регистра) или string-equal (без учета регистра).

однако эти функции также принимают символы и смеси символов и строк.

(assoc "ABC" list :test #'string=) найдет не только ключ "ABC", но и любой символ, которого зовут "ABC", например, символ :abc или cl-use:abc или mypackage:abc.

универсальный equal и equalp функции для сравнение любых двух объектов не имеет такого поведения. Как и вышеупомянутые два, equal и equalp, соответственно, чувствительны к регистру и нечувствительны. Однако они также сравнивают другие виды объектов.

в отличие от string= и string-equal, equal и equalp не считайте строки и символы эквивалентными, то есть (equalp "FOO" 'FOO) -> nil. Они также не считают эквивалентными символы, имеющие одно и то же имя: (equalp 'foo :foo) -> nil. Когда оба аргумента являются символами equal и equalp применить тот же Тест, что и


(assoc "foot" ggg :test #'string-equal)

или

(assoc "foot" ggg :test #'string=)

в зависимости от того, хотите ли вы сравнение с учетом регистра.


? (assoc "foot" ggg :test #'equalp)
("foot" 2)

Как уже указывали другие, вы можете использовать различные типы ключей, как описано в HyperSpec:

(setq alist '(("one" . 1)("two" . 2))) =>  (("one" . 1) ("two" . 2))
(assoc "one" alist) =>  NIL
(assoc "one" alist :test #'equalp) =>  ("one" . 1)