Lisp列表打印

时间:2011-11-10 18:25:56

标签: lisp common-lisp

我对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文档似乎对我没有任何作用。感谢。

2 个答案:

答案 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

(尾部nilformat的输出,不会打印到输出流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)))