Tobias C. Rittweiler <tcr@freebits.de.invalid> wrote:
+---------------
| Ron Garret <rNOSPAMon@flownet.com> writes:
| > Here's a function that does what the Python string.join function does:
| > (defun join (l &optional (delim ""))
| > (format nil (format nil "~~{~~A~~#[~~:;~A~~]~~}" delim) l))
| > Is there a way to do this with only a single call to format?
|
| If you don't mind a consing solution, what about
| (format nil "~:{~A~A~}" (loop for word in list
| collect (list word delim)))
+---------------
Your solution appends a spurious final "delim", e.g.:
> (let ((list '(a b c))
(delim #\,))
(format nil "~:{~A~A~}" (loop for word in list
collect (list word delim))))
"A,B,C,"
>
But you can fix that with a bit of uglification:
> (let ((list '(a b c))
(delim #\,))
(format nil "~:{~A~^~@[~A~]~}"
(loop for tail on list
collect (list (first tail)
(when (rest tail) delim)))))
"A,B,C"
>
which can be simplified considerably by changing the LOOP iterator
from FOR...IN to FOR...ON, to allow lookahead, and *not* using sublists:
> (let ((list '(a b c))
(delim #\,))
(format nil "~{~A~^~A~}" (loop for tail on list
collect (first tail)
when (rest tail)
collect delim)))
"A,B,C"
>
But if you're going to allow LOOP, then why use FORMAT at all?!?
Since FORMAT probably uses WITH-OUTPUT-TO-STRING "under the hood",
just do so directly:
> (let ((list '(a b c))
(delim #\,))
(with-output-to-string (s)
(loop for tail on list
do (princ (first tail) s)
(when (rest tail)
(princ delim s)))))
"A,B,C"
>
Those still awake will note that Joshua Taylor suggested this two days ago
in <news:deaba798-6a05-4ce5-a573-10ed2de2722c@41g2000hsh.googlegroups.com>,
except he used DO & WRITE-STRING and the above uses LOOP & PRINC.
-Rob
p.s. To *really* beat a dead horse, we can merge this with the
"so something different the first time" thread [remember that?
"Subject: Multiple arguments to mapcar?"], switch back to FOR...IN,
rearrange things a bit, and get:
> (let ((list '(a b c))
(delim #\,))
(with-output-to-string (s)
(loop for word in list
and first = t then nil
do (unless first
(princ delim s))
(princ word s))))
"A,B,C"
>
p.p.s. It must be really late here, or I never
could have even *considered* this version: ;-} ;-}
> (let ((list '(a b c))
(delim #\,))
(with-output-to-string (s)
(loop for word in list
and maybe-delim = "" then delim
do (princ maybe-delim s)
(princ word s))))
"A,B,C"
>
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607