我经常想要输出列表并在列表中打印它们的位置,例如
'(a b c) 会成为 "1:A 2:B 3:C"
由于FORMAT已经支持迭代给定列表,我想知道它是否也提供某种计数指令?
例如,FORMAT字符串可能看起来像这样:"~{~@C:~a~}"反之亦然~@C.
如果您想要一个无聊的答案,请转到:
(format T "~:{~a:~a ~}" (loop for i from 0 for e in '(x y z) collect (list i e)))
Run Code Online (Sandbox Code Playgroud)
现在换一个更有意思的!与@ Renzo的答案类似,它使用Tilde指令来实现其工作.
(defvar *count* 0)
(defvar *printer* "~a")
(defun iterate-counting (stream arg c at)
(declare (ignore c))
(let ((*count* (if at -1 0)))
(destructuring-bind (*printer* delimiter &rest args) arg
(format stream (format NIL "~~{~~/iterate-piece/~~^~a~~}" delimiter) args))))
(defun iterate-piece (stream arg &rest dc)
(declare (ignore dc))
(incf *count*)
(format stream *printer* *count* arg))
Run Code Online (Sandbox Code Playgroud)
这使用两个特殊变量来使其既线程安全又允许嵌套.我不会说使用它很方便.列表参数的第一项必须是格式字符串,表示如何打印参数和计数器.对于这样的格式列表,第一个参数是计数器,第二个参数是要列出的实际项目.如果需要使用星号指令,可以切换它们.第二项应该是一个字符串,作为每个项目之间的分隔符打印.最后,列表的其余部分必须是要打印的实际项目.
(format T "~/iterate-counting/" '("~a:~a" " " x y z))
=> 1:X 2:Y 3:Z
(format T "~/iterate-counting/" '("~a:~/iterate-counting/" " " ("~a>~a" "," 0 1 2) ("~a>~a" "," a b c) ("~a>~a" "," x y z)))
=> 1:1>0,2>1,3>2 2:1>A,2>B,3>C 3:1>X,2>Y,3>Z
Run Code Online (Sandbox Code Playgroud)
如果您希望它从零开始计数,请将以下@修饰符添加到iterate-counting:
(format T "~@/iterate-counting/" '("~a:~a" " " x y z))
=> 0:X 1:Y 2:Z
Run Code Online (Sandbox Code Playgroud)
我不会亲自使用这个,因为如果你偶然发现这个指令,那么发生的情况远非如此明显.对于潜在的未来读者来说,为此编写量身定制的功能可能会比尝试使用/使用更加困惑format.