Lisp列表打印

Lisp列表打印,lisp,common-lisp,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 关于如何实现这一点有什么想法吗?format函数有点混乱,HyperSpec文档似乎对我没有任何帮助。谢谢。我假设您要打印每个列表,插入空格以使元素适合最大列表长度 虽然我相信可以通过几乎单个的格式调用来打印,但最好将打印分为几个功能: (defun format-list

我在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

关于如何实现这一点有什么想法吗?format函数有点混乱,HyperSpec文档似乎对我没有任何帮助。谢谢。

我假设您要打印每个列表,插入空格以使元素适合最大列表长度

虽然我相信可以通过几乎单个的
格式调用来打印,但最好将打印分为几个功能:

(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)
条件,您可以使用下一个函数,而不是我的原始代码中的最后两行(在函数样式中,您也可以使用
循环
而不是
减少
,使其功能更少,更像CL):


与所有工具一样,格式也有其局限性,它不太适合此类问题。如果不使用
~?
~/
的黑色魔术,您或其他人将来可能无法理解的纯格式可能是以下代码:

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个元素数量相同的列表,然后可以通过
格式
进行处理

您可以在Peter Seibel的优秀Lisp书籍的相应章节中找到有关
格式的更多信息:

编辑

如果列表数量可变,且每个列表都比前一个列表大两倍,则还需要事先准备格式字符串:

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
。如果您想从这个函数中获取字符串,请使用
nil
作为
format
的输出流。)

您的问题不清楚您的输入和输出格式到底是什么。为什么第一行中的元素的间距比其他元素大?输入元素是文字“X”符号吗?等等。这是一个硬编码的列表结构吗?i、 e.X符号可以更改,但您将有三个列表(或使用destructuring bind来实现相同的列表)?如果是这样的话,所有X符号的宽度都是一个字符吗?主列表中的列表数量是可变的,并且总是比前一个列表多3个元素。@pirezas:所以你不需要任何格式和空格等,只需要在新行打印下一行就行了?例如,我需要空格,在每一行我都需要打印一些东西,比如:X+Space*(NumRows CurrentRowNumber)非常感谢,这几乎就是我需要的。唯一需要的是它在末尾打印一个NIL,对此有什么想法吗?我相信你可以在REPL中尝试这段代码
NIL
这里不是打印部分,只是返回值,所以不用担心。谢谢,它现在可以工作了。但是关于NIL,即使它是返回值,我不能让它消失吗?或者计算列表或其他东西…@pirezas:Lisp中的任何形式(函数、宏、变量、表达式)都会返回一些值。您无法避免在REPL中打印返回值。但是,您可以将
(格式t…
更改为
(格式nil…
),从而返回字符串,而不是打印字符串并返回nil。
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