common-lisp中更好的pythonic`join` [英] Nicer pythonic `join` in common-lisp
问题描述
在Edi Weitz的cl食谱中,对于pythonic join
,建议使用以下功能:
In Edi Weitz's cl cookbook, for the pythonic join
, this function is suggested:
(defun join (separator list)
(with-output-to-string (out)
(loop for (element . more) on list
do (princ element out)
when more
do (princ separator out))))
但是,我以某种方式思考,必须有一种以另一种方式表达join
的方法,也许使用format
的功能...
However, somehow I was thinking, there must be a way to express join
in another way, maybe using format
's capabilities ...
在Seibel的书中(在关于format
的章节中),我们发现列表中的字符串通过分隔符连接到单个字符串
", "
通过:
In Seibel's book, (in the chapter about format
) we find joining of strings in a list to a single string with the separator
", "
by:
(defvar l '("a" "b" "c"))
(format nil "~{~A~^, ~}" l)
;; "a, b, c"
这是一个pythonic联接,非常简洁; ~^
指令使", "
仅在最后一个元素之前添加,而在后面没有元素时不添加.
Which is a pythonic join and which is very terse; the ~^
directive makes that ", "
is added only until just before the last element and not added when no element is following.
但是,这里的分隔符字符串", "
是format指令的一部分.
However, here, the separator string ", "
is part of the format directive.
一个棘手的案例是(defvar sep #\Tab)
.
如果sep "#\Tab"
的表示形式可以在此format指令的中间放置为分隔符,则会导致:
A tricky case is e.g. (defvar sep #\Tab)
.
If the representation of sep "#\Tab"
literally can be placed as a separator in midst of this format directive, resulting in:
(format nil "~{~A~^#\Tab~}" l)
我们会达到目标的.
很显然,必须使用宏来生成format指令...
我尝试了类似(princ-to-string sep)
的方法,但这给出了"#\\Tab"
而不是"#\Tab"
.
Obviously, one has to use a macro to generate the format directive ...
I tried things like (princ-to-string sep)
but this gives "#\\Tab"
and not "#\Tab"
.
例如
(defmacro join (sep l)
`(format nil ,(format nil "~{~A~}" `("\~\{\~A\~\^" ,(write-to-string sep) "\~\}")) l))
但是尝试时:
(join #\Tab '("a" "b" "c"))
当然不希望得到此结果:"a#\\Tabb#\\Tabc"
,因为
This results of course is sth not desired: "a#\\Tabb#\\Tabc"
, since
(macroexpand-1 '(join #\Tab '("a" "b" "c")))
;; results in:
(FORMAT NIL "~{~A~^#\\Tab~}" L)
;; instead of:
(FORMAT NIL "~{~A~^#\Tab~}" L)
但是我看不到如何实现所需宏的这一步... 有人对此有启发吗?
But I don't see how to achieve this step to the desired macro ... Has anybody an enlightening about this?
关于元编程问题的元编程的种类...
Kind of a metaprogramming on metaprogramming problem ...
好吧,现在我知道@Rainer Joswig已经发布在 在列表中加入字符串的规范方法是什么? /a>
Okay, now I see, that @Rainer Joswig has already posted in What's the canonical way to join strings in a list?
此问题的解决方案.但是,如果有一种方法可以将"#\\Tab"
表示为"#\Tab"
,则可以得出一个更紧凑的定义.
但是以某种方式,Lisp阅读器似乎总是以字符串形式将"\Tab"
识别为一个字母.可以编写一个函数来做到这一点吗?
a solution to this problem. However, if there would be a way, to represent "#\\Tab"
as "#\Tab"
, one could come to a more compact definition.
But somehow the Lisp reader seems in a string always to recognize "\Tab"
as one letter. Is it possible to write a function to do that?
备注
在R中,特别是对于元编程,存在诸如as.name("myvar")
之类的函数,这些函数从字符串"myvar"中生成符号myvar
.
和类似deparse(substitute(x))
的表达式,它使用符号x
并从中创建文字字符串"x"
. Deparse后退print()
命令的执行,从而转义特殊符号. deparse(deparse(substitute(x)))
例如生成"\"x\""
-尽管围绕此表达式的parse(text = ... )
会再次使"x"
成为parse(text = deparse(deparse(substitute(x))))
.
在common-lisp中如何实现这样的事情?
例如(a-special-function #\Tab)
导致(文字):"#\Tab"
作为字符串?
In R, there exist especially for metaprogramming, functions like as.name("myvar")
which generate the symbolmyvar
out of the string "myvar".
and expressions like deparse(substitute(x))
which takes the symbol x
and creates out of it a literal string "x"
. Deparse steps back the execution of print()
commands, whereby escaping special symbols. deparse(deparse(substitute(x)))
would e.g. generate "\"x\""
- While parse(text = ... )
around this expression would make out of it "x"
again parse(text = deparse(deparse(substitute(x))))
.
How such things could be achived in common-lisp?
e.g.(a-special-function #\Tab)
resulting in (literal): "#\Tab"
as a string?
结语
谢谢@Sylwester !!他没有宏就解决了它.而且非常优雅!
Thank you @Sylwester!! He solved it without macro. And very elegantly!
推荐答案
您的问题是您尝试将#\Tab
添加到格式中,但这就是使用文字的方式.如果您只是在格式字符串中插入了制表符或包含它的字符串,它将执行您想要的操作:
Your problem is that you try to add #\Tab
to the format, but that is just how you do it with literals. If you just inserted a tab character or a string consisting of it in the format string it will do what you want:
(defun join (l &key (sep ", "))
(format nil (format nil "~a~a~a" "~{~a~^" sep "~}") l))
(join '(1 2 3))
; ==> "1, 2, 3"
(join '(1 2 3) :sep #\Tab)
; ==> "1 2 3"
这篇关于common-lisp中更好的pythonic`join`的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!