Lisp初学者在这里。
我有两个这种长度相同的字符串列表:
keys = ("abc" "def" "gh" ...)
values = ("qwe" "opr" "kmn" ...)
我需要从这些列表构造哈希表或关联列表(无论是哪种构造方法都很容易并且可以从中快速获取值)。由于配对,它们处于适当的索引中。
我知道我可以通过迭代来映射它们。但是我想采用一种更具声明性的方式,如果可以的话,我正在寻找一种干净的方式。
Lisp初学者在这里。
我有两个这种长度相同的字符串列表:
keys = ("abc" "def" "gh" ...)
values = ("qwe" "opr" "kmn" ...)
我需要从这些列表构造哈希表或关联列表(无论是哪种构造方法都很容易并且可以从中快速获取值)。由于配对,它们处于适当的索引中。
我知道我可以通过迭代来映射它们。但是我想采用一种更具声明性的方式,如果可以的话,我正在寻找一种干净的方式。
有一个名为PAIRLIS
的专用函数,它可以完成您想要建立的关联列表:
USER> (pairlis '("abc" "def" "gh")
'("qwe" "opr" "kmn"))
(("gh" . "kmn") ("def" . "opr") ("abc" . "qwe"))
请注意,顺序是相反的,但这取决于实现方式。因为您的键是唯一的,所以这里的顺序无关紧要。
然后,您可以使用流行的alexandria库从该库构建哈希表:
USER> (alexandria:alist-hash-table * :test #'equalp)
#<HASH-TABLE :TEST EQUALP :COUNT 3 {101C66ECA3}>
在这里,我将哈希表与测试equalp
一起使用,因为您的密钥是字符串。
NB。 *
符号指的是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 ect之类的循环……
(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))