Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

format - Help with printing a table

Tags:

format

lisp

This question will probably end in a facepalm, but I've tried for a while and am still stuck despite reading through the hyperspec.

Basically what I want to do is something like

(format t "~{|~{ ~5d~}|~%~}" '((1 23 2 312) (23 456 1 7890)))

but instead of hard-coding the 5 it should be calculated from the list (length of longest element from any nested list + 1) to give something like

|    1    23     2   312|
|   23   456     1  7890|      

Maybe I'm thinking way too complicated here and there is an easier way to do what I want, but I think I ran myself into a mental corner that I can't get out of.

like image 427
Michael Kohl Avatar asked Jan 06 '11 18:01

Michael Kohl


2 Answers

I think that you have two options: let the format magic go and use other looping constructs or generate the format string itself:

(defun facepalm-printer (lol)
  (format t (format nil "~~{|~~{ ~~~ad~~}|~~%~~}"
                    (longest-member lol))
          lol))

The definition of longest-member is left as an exercise to the reader.

like image 124
Svante Avatar answered Oct 10 '22 05:10

Svante


Assuming the required width is bound to width, then you can do this:

(format t "~{|~{ ~Vd~}|~%~}" width '((1 23 2 312) (23 456 1 7890)))

5 has been replaced by V and width has been added as an argument to FORMAT/

edit: original answer did not correctly account for the nested directives

In a format control string V may be used in place of any constant value, indicating that the corresponding value is to be taken from the argument list instead.

You can try this:

(setf width 5)
(setf data '((1 23 2 312) (23 456 1 7890)))

(format t "~{|~{ ~{~Vd~}~}|~%~}"
  (mapcar #'(lambda (r) (mapcar #'(lambda (v) (list width v)) r)) data) )

This format string requires the desired width to precede each value. The (mapcar ...) expression accomplishes this.

like image 44
WReach Avatar answered Oct 10 '22 05:10

WReach