我该如何在Common Lisp中格式化一个alist?

5

我开始学习写一些通用Lisp代码,并且正在逐渐理解如何将东西连接在一起并格式化它们。

假设我有一个类似这样的关联列表:

(defvar *map* '((0 . "zero") (1 . "one") (2 . "two")))

我该如何以这种格式进行格式化?
0: zero
1: one
2: two

我在想类似于 (format t "~{~{~a: ~a~}~%~}" *map*) 这样的东西,但因为"zero"不是一个列表,所以会出错。

当然,执行 (format t "~{~a~%~}" *map*) 会输出:

(0 . "zero")
(1 . "one")
(2 . "two")

我想让它按照预期的方式工作,但这并不完全是我想要的。有没有比仅使用 (dolist (entry *mapping*) (format t "~a: ~a~%" (car entry) (cdr entry))) 更好的方法?

5个回答

11

Freenode上的#cl-gardeners频道建议使用以下方式进行解构循环绑定:

(loop for (a . b) in *mapping*
  do (format t "~a: ~a" a b))

7

你说得没错,从FORMAT中似乎没有办法分解cons单元。

如果你定义另一个函数来格式化单个关联:

(defun print-assoc (stream arg colonp atsignp)
  (format stream "~A: ~A" (car arg) (cdr arg)))

那么很简单:
(format t "~{~/print-assoc/~%~}" *map*)

我不确定这是否是一种改进。一方面,它有点更加复杂,但另一方面,它将print-assoc拆分成一个(可重用的)函数,这可能会很有用。


6
在格式中,应使用合格的函数名称。FORMAT解析package中指定的符号,而在调用格式时,你永远不会知道package是什么。 - dmitry_vk

4

我认为这里的经验教训是不要使用带点的列表作为您的 alist。虽然您可以节省一个 cons 单元,但您会放弃所有漂亮的序列和列表函数。这并不值得。如果使用完整形式的列表,您的格式示例就很简单:

(defvar *map* '((0 "zero") (1 "one") (2 "two")))
(format t "~:{~a: ~a~}" *map*)

1

我认为没有比使用 map() 更好的办法:

(format t "~{~a~%~}"
  (map 'list
    #'(lambda (entry)
      (format nil "~a: ~a" (car entry) (cdr entry))
    *map*))

1

使用以下方法将alist单元格(a . 2)转换为列表(a 2)

(mapcar #'(lambda (x) `(,(car x) ,(cdr x))) *map*)

然后按照格式处理。

例如,将 ((a . 2) (b . 3)) 打印为 "a=2&b=3"

使用

(format t "~{~{~a~^=~}~^&~}" (mapcar #'(lambda (x) `(,(car x) ,(cdr x))) *map*))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接