在 Lisp 中映射两个字符串列表(以简短的方式)?

Mapping two string lists (in a short way) in Lisp?

这里是 Lisp 初学者。

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

  keys = ("abc" "def" "gh" ...)
  values = ("qwe" "opr" "kmn" ...)

我需要从这些列表构建散列-table 或关联列表(以易于构建和快速获取值为准)。由于他们的配对,他们在正确的索引中。

我知道我可以通过迭代来映射它们。但是我想采用一种更具声明性的方式,并且我正在寻找一种干净的方式来实现这一点,如果可以的话。

有一个名为 PAIRLIS 的专用函数可以完全满足您构建关联列表的需求:

USER> (pairlis '("abc" "def" "gh")
               '("qwe" "opr" "kmn"))
(("gh" . "kmn") ("def" . "opr") ("abc" . "qwe"))

请注意,顺序是相反的,但这取决于实现。这里的顺序无关紧要,因为您的密钥是唯一的。

然后,您可以使用流行的 alexandria 库从中构建哈希-table:

USER> (alexandria:alist-hash-table * :test #'equalp)
#<HASH-TABLE :TEST EQUALP :COUNT 3 {101C66ECA3}>

这里我使用哈希-table 和测试 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*)

映射对于 common 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))