【问题标题】:Pretty-print values in fixed-width fields固定宽度字段中的漂亮打印值
【发布时间】:2014-11-12 18:40:07
【问题描述】:

我想在固定宽度的字段中漂亮地打印一个由列名和值组成的矩阵。这是我写的代码:

(defstruct
  (matrix
    (:print-function (lambda (my-matrix stream depth)
                     (declare (ignore depth))
                     (let* ((dimensions (matrix-dimensions my-matrix))
                            (column-names (matrix-column-names my-matrix))
                            (values (matrix-values my-matrix))
                            (number-of-rows (nth 0 dimensions))
                            (number-of-columns (nth 1 dimensions)))
                       (progn (loop :for i :upto number-of-columns
                                 :do (if (< i number-of-columns)
                                         (format stream (nth i column-names))
                                         (format stream "~%")))
                              (loop :for j :upto (1- number-of-rows)
                                 :do (loop :for k :upto number-of-columns
                                        :do (if (< k number-of-columns)
                                                (format stream (write-to-string (aref values j k)))
                                                (format stream "~%")))))))))
  dimensions
  column-names
  values)

但是,如果我运行这段代码,我会得到以下结果:

CL-USER> (make-matrix :dimensions '(3 2)
                  :column-names '("Michael" "Alexandra")
                  :values (make-array '(3 2) :initial-contents '((54 34) (65 78) (49 38))))
MichaelAlexandra
5434
6578
4938

如何编辑我的 :print-function(更具体地说是它的格式部分),以便在固定宽度的字段中整齐地打印列名和值?

我读到有一个 ~w 格式的指令用于此目的,但并没有真正掌握它是如何工作的。

【问题讨论】:

标签: format lisp common-lisp multidimensional-array


【解决方案1】:

format 指令中使用"~NN"

(defstruct
  (matrix
    (:print-function (lambda (my-matrix stream depth)
                       (declare (ignore depth))
                       (let* ((dimensions (matrix-dimensions my-matrix))
                              (column-names (matrix-column-names my-matrix))
                              (values (matrix-values my-matrix))
                              (number-of-rows (nth 0 dimensions))
                              (number-of-columns (nth 1 dimensions)))
                         (loop :for i :upto number-of-columns
                           :do (if (< i number-of-columns)
                                   (format stream "~10s" (nth i column-names))
                                   (terpri stream)))
                         (loop :for j :upto (1- number-of-rows)
                           :do (loop :for k :upto number-of-columns
                                 :do (if (< k number-of-columns)
                                         (format stream "~10s" (aref values j k))
                                         (terpri stream))))))))
  dimensions
  column-names
  values)

PS。 let中不需要progn

【讨论】:

  • 这很好用。我还没有解决的唯一剩下的问题是如何打印不带引号的列名。截至目前,如果我运行 (make-matrix :dimensions '(3 2) :column-names '("Michael" "Alexandra") :values (make-array '(3 2) :initial-contents '((54 34) (65 78) (49 38)))), "Michael" 和 "Alexandra" 将被打印到引号中。如何在不带引号的情况下打印它们?
  • 使用~A 代替~S 作为名称。
【解决方案2】:

我会用 CLOS,Common Lisp 对象系统来编写它。

具有三个 initargs 的矩阵类:

(defclass matrix ()
  ((dimensions   :initarg :dimensions)
   (column-names :initarg :column-names)
   (values       :initarg :values)))

print-matrix 方法:

(defmethod print-matrix ((matrix matrix) &optional (stream *standard-output*))
  (with-slots (dimensions column-names values)
      matrix
    (destructuring-bind (number-of-rows number-of-columns)
        dimensions
      (dotimes (i number-of-columns)
        (format stream "~10a" (nth i column-names)))
      (terpri stream)
      (dotimes (j number-of-rows)
        (dotimes (k number-of-columns)
          (format stream "~10s" (aref values j k)))
        (terpri stream)))))

试试看:

? (print-matrix (make-instance 'matrix
                  :dimensions '(3 2)
                  :column-names '("Michael" "Alexandra")
                  :values (make-array '(3 2)
                            :initial-contents '((54 34) (65 78) (49 38)))))
Michael   Alexandra 
54        34        
65        78        
49        38        

更改类的默认打印机:

(defmethod print-object ((matrix matrix) stream)
  (print-matrix matrix stream))

【讨论】:

  • 您为什么要使用 CLOS Rainer?我知道类比结构提供更多的选项,所以我认为处理类比处理结构时计算成本更高。为什么不只使用结构,只要您不对多重继承等特性进行分类?
  • @Alexandre:始终使用 CLOS。仅在您绝对需要(但未获得)性能时才使用结构。
  • 为什么建议始终使用 CLOS?
  • @Alexandre:为什么要使用两种方式来定义记录?选择更好地融入 Lisp 哲学的更好的。那是克洛斯。始终如一。 Knuth 在 1974 年:我们应该忘记小的效率,比如大约 97% 的时间:过早的优化是万恶之源。
  • defstruct IMNSHO 的一个巨大 优势是存在一个有用 默认print-object 方法。 (我知道为什么defclass没有这样的方法)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-04
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 1970-01-01
  • 2012-01-17
相关资源
最近更新 更多