我对lisp格式功能有些麻烦。我有以下列表:
((X X X)(X X X X X X)(X X X X X X X X X))
我需要按以下格式打印:
X X X
XX XX XX
XXXXXXXXX
有关如何实现这一目标的任何想法?格式函数有点令人困惑,HyperSpec文档似乎对我没有任何作用。感谢。
答案 0 :(得分:3)
像每个工具format
都有其局限性,并且它不适合这些问题。可能是你用普通格式获得的最好的,而不是诉诸~?
或~/
的黑魔法技巧,你或其他任何人将来可能都不会理解这个代码:
CL-USER> (format t "~{~{~A ~}~%~}"
'((X X X) (X X X X X X) (X X X X X X X X X)))
X X X
X X X X X X
X X X X X X X X X
如果您想获得复杂的输出结构,请尝试进行一些预处理。 比如,如果列表的格式是硬编码的,您可以使用:
(format t "~{~{~6A~} ~%~}"
(mapcar (lambda (l)
(loop :for i :from 0 :to (1- (length l)) :by (/ (length l) 3)
:collect (format nil "~{~A ~}"
(subseq l i (+ i (/ (length l) 3))))))
'((X X X) (X X X X X X) (X X X X X X X X X))))
这里我们首先将列表的项目收集到每个列表的相同数量的组中,打印它们,这样就可以得到3个具有相同元素数量的列表,然后可以由format
处理。
您可以在Peter Seibel的优秀Lisp书的相应章节中找到有关format
的更多信息:http://gigamonkeys.com/book/a-few-format-recipes.html
修改强>
如果你有一个可变数量的列表,每个列表比前一个更大,你还需要事先准备格式字符串:
CL-USER> (defun format-custom-list (list)
(format t (format nil "~~{~~{~~~DA~~} ~~%~~}" (* 2 (length list)))
(mapcar (lambda (l)
(let* ((len (length l))
(len/3 (/ len 3)))
(loop :for i :from 0 :to (1- len) :by len/3
:collect (format nil "~{~A ~}"
(subseq l i (+ i len/3))))))
list)))
CL-USER> (format-custom-list '((X X X) (X X X X X X) (X X X X X X X X X)
(X X X X X X X X X X X X)))
X X X
X X X X X X
X X X X X X X X X
X X X X X X X X X X X X
NIL
(尾部nil
是format
的输出,不会打印到输出流t
。如果要从此函数中获取字符串,请使用{{ 1}}作为nil
的输出流。)
答案 1 :(得分:2)
我假设您要打印每个列表,插入空格以使元素符合最大列表长度。
虽然我相信可以通过几乎format
次呼叫来打印它,但最好将打印分成几个功能:
(defun format-list (stream lst space-count)
(let ((spaces (make-string 5 :initial-element #\Space))) ;; create string of spaces to insert
(let ((fmt (concatenate 'string "~{~a" spaces "~}~%")) ;; create formatting string
(format stream fmt lst)))))
(defvar full-list '((X X X)(X X X X X X)(X X X X X X X X X)))
(defvar max-list-length (max (mapcar length full-list))) ;; find length
(mapcar
#'(lambda (lst) (format-list t lst (/ (- max-list-length (length lst)) (length lst))))
full-list)
<强> UPD。强>
对于X + Space * (NumRows - CurrentRowNumber)
条件,您可以在我的原始代码中使用下一行而不是最后两行(在功能样式中,您也可以使用loop
代替reduce
来降低功能性更多CL-like):
(format-list-of-lists (lst)
(let ((num-rows (length lst)))
(reduce #(lambda (cur-row sub-list) (format-list t sub-list (- num-rows cur-row)) (1+ cur-row))
lst)))