List 在Lisp中映射两个字符串列表(简单地说)?

List 在Lisp中映射两个字符串列表(简单地说)?,list,lisp,common-lisp,hashtable,List,Lisp,Common Lisp,Hashtable,这里是Lisp初学者 我有两个相同长度的字符串列表: keys = ("abc" "def" "gh" ...) values = ("qwe" "opr" "kmn" ...) 我需要从这些列表中构造哈希表或关联列表(无论哪一个易于构造,从中快速获取值)。由于它们是成对的,所以它们处于适当的索引中 我知道我可以用迭代来映射它们。但我想用一种更具声明性的方式,我正在寻找一种干净的方式,如果可以的话 有一个名为的专用函数,它的功能正是您想要构建关联列表的功能: USER> (pai

这里是Lisp初学者

我有两个相同长度的字符串列表:

  keys = ("abc" "def" "gh" ...)
  values = ("qwe" "opr" "kmn" ...)
我需要从这些列表中构造哈希表或关联列表(无论哪一个易于构造,从中快速获取值)。由于它们是成对的,所以它们处于适当的索引中


我知道我可以用迭代来映射它们。但我想用一种更具声明性的方式,我正在寻找一种干净的方式,如果可以的话

有一个名为的专用函数,它的功能正是您想要构建关联列表的功能:

USER> (pairlis '("abc" "def" "gh")
               '("qwe" "opr" "kmn"))
(("gh" . "kmn") ("def" . "opr") ("abc" . "qwe"))
请注意,顺序是相反的,但这取决于实现。这里的顺序并不重要,因为您的密钥是唯一的

然后,您可以使用流行库从以下内容构建哈希表:

USER> (alexandria:alist-hash-table * :test #'equalp)
#<HASH-TABLE :TEST EQUALP :COUNT 3 {101C66ECA3}>
USER>(alexandria:alist哈希表*:test#'equalp)
#
这里我使用一个带有test
equalp
的哈希表,因为您的键是字符串


注意。符号指的是REPL中的最后一个主值。您可以执行诸如mapcar之类的操作,为您处理迭代,而不是手动输入某种循环进行迭代。例如:

(defvar *first-names* '("tom" "aaron" "drew"))
(defvar *last-names* '("brady" "rogers" "brees"))
(defvar *names-table* (make-hash-table))
我们可以创建一个包含两组名称的列表,然后创建一个哈希表(或列表,如果您愿意的话)。然后,我们可以简单地使用mapcar通过我们的列表进行映射,而不是手动输入循环,如do、dolist、dotimes、loop等

(mapcar #'(lambda (first last)
           (setf (gethash first *names-table*) last))
       *first-names*
       *last-names*)

映射对于公共lisp中的列表特别有用

请注意,与
pairlis
&c一样,正常映射函数(如
mapcar
)实际上采用多个列表参数,并调用每个参数上映射的函数。因此,
pairlis
所做的(部分)简单版本可能是:

(defun kv->alist (keys values)
  (mapcar #'cons keys values))
(事实上,在某些情况下,这比pairlis有优势:结果的顺序是确定的。)

如果要制作哈希表:

(defun kv->ht (keys values &key (test #'eql))
  (let ((ht (make-hash-table :test test)))
    (mapc (lambda (k v)
            (setf (gethash k ht) v))
          keys values)
    ht))

Tx!,一个简短的问题:我知道我可以从哈希表中获得O(n)复杂度的值,但是assoc list呢?@drh0use列表是一个单链接列表,因此需要线性时间来根据键检索值。alist的优点是它是功能性的,您只需将新的cons单元格放在现有列表的前面即可对值进行阴影处理:如果调用
(assoc:a'(:a.0)(:b.1)(:a-1))
,您将获得
:a
(具有0值的单元格)的第一个匹配项。另见