【问题标题】:Lisp List PrintingLisp 列表打印
【发布时间】:2011-11-10 18:25:56
【问题描述】:

我在 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 文档似乎对我没有任何帮助。谢谢。

【问题讨论】:

  • 从您的问题中不清楚您的输入和输出格式到底是什么。为什么第一行中的元素比其他元素间隔更多?输入元素是文字'X 符号吗?等等
  • 这是一个硬编码的列表结构吗?即 X 符号可以更改,但您将拥有三个列表(或使用解构绑定来实现相同)?如果是这样的话,所有 X 符号的宽度都是一个字符吗?
  • 主列表中的列表数量是可变的,并且总是比前一个多3个元素。
  • @pirezas:所以您不需要任何格式、空格等,只需在新行打印下一行?
  • 我需要空格,例如,在每一行我需要打印如下内容:X + Space*(NumRows-CurrentRowNumber)

标签: lisp common-lisp


【解决方案1】:

就像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。如果你想从这个函数中得到一个字符串,使用nil作为format' s 输出流。)

【讨论】:

  • 非常感谢,这几乎就是我所需要的,唯一的问题是它最后打印了一个 NIL,对此有什么想法吗?
  • 我相信你在 REPL 中尝试过这段代码。 NIL这里不是打印部分,只是返回值,不用担心。
  • 感谢它现在有效。但是对于NIL,即使它是返回值,我不能让它消失吗?或者评估列表什么的......
  • @pirezas:Lisp 中的任何形式(函数、宏、变量、表达式)总是返回一些值。您无法避免在 REPL 中打印返回值。但是,您可以将 (format t ...) 更改为 (format nil ...),从而返回字符串而不是打印字符串并返回 nil。
【解决方案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) 条件,您可以在我的原始代码中使用 next 函数而不是最后两行(在函数式样式中,您还可以使用 loop 而不是 reduce 以使其功能更少,更像 CL):

(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)))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-09
    • 2022-01-16
    • 2013-08-27
    • 2013-03-24
    相关资源
    最近更新 更多