2011-01-06 67 views
6

这个问题可能会以facepalm结束,但我已经尝试了一段时间,尽管通过hyperspec阅读,但仍然卡住了。格式 - 帮助打印表格

基本上就是我想要做的是一样的东西

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

而是硬编码的5应该从列表来计算(从任何嵌套列表+ 1最长的元素的长度)得到的东西像

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

也许我想太复杂这里还有一个更简单的方法做我想要的,但我觉得我跑自己变成了一个精神的角落,我不能离开。

+0

可能有一个`〜`控件来做你想做的事情,但我只需要2步完成这一步:计算最宽的元素,然后使用该元素构建一个格式化字符串(使用格式!),然后调用格式来建立表格。所以这是一个3线功能,而不是1线功能。 :-) – Ken 2011-01-06 19:21:26

回答

3

假设所需宽度势必 width,则可以做到这一点:

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

5已取代 Vwidth已经被添加作为参数传递给 FORMAT/

编辑:原始答案没有正确解释嵌套指令

在格式中,可以使用控制字符串V来代替任何常量值,指示相应的值将从参数列表中取而代之。

你可以试试这个:

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

此格式字符串要求所需的宽度先于每个值。 (mapcar ...)表达式完成此操作。

+1

+1好的答案。最大宽度至少易于计算(至少如果所有数字都是正数)。例如,`(1+(apply#'max(mapcar#'(lambda(x)(floor(log x 10)))'(1 10 100 1000 200000))))`。 – 2011-01-06 20:48:55

5

我认为你有两个选择:让format魔法去使用其他循环结构或生成格式字符串本身:

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

longest-member的定义作为练习留给读者。