I'm beginning to write me some Common Lisp and am just getting the hang of consing things together and formatting them.
Let's suppose I have an alist, like this:
(defvar *map* '((0 . "zero") (1 . "one") (2 . "two")))
How do I format it like this?
0: zero
1: one
2: two
I was thinking something like (format t "~{~{~a: ~a~}~%~}" *map*)
, but that gives an error because "zero" isn't a list and you can't take the car of it.
Of course, doing (format t "~{~a~%~}" *map*)
prints
(0 . "zero")
(1 . "one")
(2 . "two")
like it's supposed to, but it's not quite what I want. Is there a better way to do this than just (dolist (entry *mapping*) (format t "~a: ~a~%" (car entry) (cdr entry)))
?
The #cl-gardeners channel on Freenode suggests doing a destructuring loop bind like this:
(loop for (a . b) in *mapping*
do (format t "~a: ~a" a b))
You're right, in that it doesn't look like there's any way to pick apart a cons cell from FORMAT.
If you define another function to format a single association:
(defun print-assoc (stream arg colonp atsignp)
(format stream "~A: ~A" (car arg) (cdr arg)))
then it's easy:
(format t "~{~/print-assoc/~%~}" *map*)
I'm not sure if this is an improvement or not. On the one hand, it's a little more complex, but on the other hand, it does break out print-assoc into a (reusable) function, which could be useful.
I think the takeaway lesson here is really not to use dotted lists for your alists. You save one cons cell, sure, but you give up all the nice sequence and list functions. It's just not worth it. Your formatting example is trivial with fully formed lists:
(defvar *map* '((0 "zero") (1 "one") (2 "two")))
(format t "~:{~a: ~a~}" *map*)
I don't think there's a better way to do it; I would used map()
:
(format t "~{~a~%~}"
(map 'list
#'(lambda (entry)
(format nil "~a: ~a" (car entry) (cdr entry))
*map*))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With