From: DaveNlp
Subject: concatenate atoms into string
Date: 
Message-ID: <dHYdb.448$1d.10419@twister1.libero.it>
Does a similar function exists?

(defun join (wlist sepchr)
  (let ((string nil))
    (dolist (sym wlist string)
      (setf string
        (concatenate 'string
          string (if string sepchr nil) (string sym))))))

>(join '("happy" "new" "year") "-")
>"happy-new-year"

Thanks you.
DaveNlp.

From: Marco Antoniotti
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <3F7868BC.5040403@cs.nyu.edu>
FORMAT is your friend

(defun join (word-list separator)
   (if word-list
      (format nil "~A~:{~C~A}" (first word-list)
                               (mapcar (lambda (w)
                                          (list separator w))
                                       (rest word-list)))
      ""))

in alternative

(defun join (word-list separator)
   (if word-list
     (with-output-to-string (s)
        (princ (first word-list) s) ; Or maybe PRIN1.
        (loop for w in word-list
              do (princ w s)
                 (princ separator s)))
     "")

Cheers
--
marco




DaveNlp wrote:
> Does a similar function exists?
> 
> (defun join (wlist sepchr)
>   (let ((string nil))
>     (dolist (sym wlist string)
>       (setf string
>         (concatenate 'string
>           string (if string sepchr nil) (string sym))))))
> 
> 
>>(join '("happy" "new" "year") "-")
>>"happy-new-year"
> 
> 
> Thanks you.
> DaveNlp.
> 
> 
From: Alan Crowe
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <86isnbdufv.fsf@cawtech.freeserve.co.uk>
Marco Antoniotti wrote
> FORMAT is your friend

You are giving me ideas. How about

(defun join (word-list separator)
    (format nil
	    (concatenate 'string "~{~A~^" separator "~}")
            word-list))

which uses ~^ to stop and not put the separator after the
last string.

Alan Crowe
From: Nils Goesche
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <ly4qyt5faq.fsf@cartan.de>
Alan Crowe <····@cawNOtech.freeSPAMserve.co.uk> writes:

> Marco Antoniotti wrote
> > FORMAT is your friend
> 
> You are giving me ideas. How about
> 
> (defun join (word-list separator)
>     (format nil
> 	    (concatenate 'string "~{~A~^" separator "~}")
>             word-list))
> 
> which uses ~^ to stop and not put the separator after the
> last string.

Nice try, but what if the separator is "~"? :-)

Regards,
-- 
Nils G�sche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x0655CFA0
From: Brian Downing
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <fJ_db.634680$o%2.292163@sccrnsc02>
In article <··················@twister1.libero.it>,
DaveNlp <(NOSPAM)·········@iol.it> wrote:
> Does a similar function exists?
> 
> (defun join (wlist sepchr)
>   (let ((string nil))
>     (dolist (sym wlist string)
>       (setf string
>         (concatenate 'string
>           string (if string sepchr nil) (string sym))))))

Well, this only makes one call to concatenate, hardly conses otherwise,
and is general for all sequences.  I like it.

(defun join-seq (type list separator)
  (let ((concatenate-args
         (cons (first list) (loop for element in (rest list)
                                  collect separator
                                  collect element))))
    (apply #'concatenate type concatenate-args)))

* (join-seq 'string '("happy" "new" "year") "-")
"happy-new-year"

* (join-seq 'vector '(#(8 0 0) #(5 5 5) #(1 2 1 2)) #("-"))
#(8 0 0 "-" 5 5 5 "-" 1 2 1 2)

* (join-seq 'list '((one two three) (four five six seven)) '(nil))
(ONE TWO THREE NIL FOUR FIVE SIX SEVEN)

* (join-seq 'string '((#\h #\a #\p #\p #\y) "new" #(#\y #\e #\a #\r)) '(#\-))
"happy-new-year"

-bcd
From: Rob Warnock
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <vdidnTzdUcZgDeWiXTWc-w@speakeasy.net>
Brian Downing  <·············@lavos.net> wrote:
+---------------
| Well, this only makes one call to concatenate, hardly conses otherwise,
| and is general for all sequences.  I like it.
| 
| (defun join-seq (type list separator)
|   (let ((concatenate-args
|          (cons (first list) (loop for element in (rest list)
|                                   collect separator
|                                   collect element))))
|     (apply #'concatenate type concatenate-args)))
+---------------

An idiom I've found myself using with LOOP to special-case
first elements is this:

  (defun join-seq (type list separator)
    (apply #'concatenate type
	   (loop for element in list
		 and first = t then nil
             unless first
	       collect separator
	     collect element)))

or, depending on the phase of the moon and what I've had for lunch,
this [note use of ON here]:

  (defun join-seq (type list separator)
    (apply #'concatenate type
	   (loop for tail on list
	     collect (car tail)
	     when (cdr tail)
	       collect separator)))

But both of these do involve a test per iteration that yours doesn't,
so are slightly less efficient I suppose.


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kaz Kylheku
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <cf333042.0309300923.4f482f99@posting.google.com>
"DaveNlp" <(NOSPAM)·········@iol.it> wrote in message news:<··················@twister1.libero.it>...
> Does a similar function exists?
> 
> (defun join (wlist sepchr)
>   (let ((string nil))
>     (dolist (sym wlist string)
>       (setf string
>         (concatenate 'string
>           string (if string sepchr nil) (string sym))))))
> 
> >(join '("happy" "new" "year") "-")
> >"happy-new-year"

This kind of repeated reduction of a sequence through a binary
operator is nicely handled functionally by REDUCE. Just take care of
the empty list case; REDUCE internally handles the case when the list
has length one:

(if wlist
  (reduce #'(lambda (x y)
              (concatenate 'string x sepchr y)) 
          wlist))

Apologies about the use of the implicit NIL result from IF. ;)
From: Pascal Costanza
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <blchoi$6tp$1@newsreader2.netcologne.de>
Kaz Kylheku wrote:

> "DaveNlp" <(NOSPAM)·········@iol.it> wrote in message news:<··················@twister1.libero.it>...
> 
>>Does a similar function exists?
>>
>>(defun join (wlist sepchr)
>>  (let ((string nil))
>>    (dolist (sym wlist string)
>>      (setf string
>>        (concatenate 'string
>>          string (if string sepchr nil) (string sym))))))
>>
>>
>>>(join '("happy" "new" "year") "-")
>>>"happy-new-year"
> 
> 
> This kind of repeated reduction of a sequence through a binary
> operator is nicely handled functionally by REDUCE. Just take care of
> the empty list case; REDUCE internally handles the case when the list
> has length one:
> 
> (if wlist
>   (reduce #'(lambda (x y)
>               (concatenate 'string x sepchr y)) 
>           wlist))
> 
> Apologies about the use of the implicit NIL result from IF. ;)

FWIW, I find the use of :initial-value clearer, as in:

(reduce (lambda (x y) (concatenate 'string x sepchr y))
         wlist
         :initial-value nil)

Then you don't have to handle the empty list.


Pascal
From: Ed Symanzik
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <pan.2003.09.30.20.29.27.459159@msu.edu>
On Tue, 30 Sep 2003 20:24:18 +0200, Pascal Costanza wrote:


> FWIW, I find the use of :initial-value clearer, as in:
> 
> (reduce (lambda (x y) (concatenate 'string x sepchr y))
>          wlist
>          :initial-value nil)
> 
> Then you don't have to handle the empty list.

Except this gives you a leading sepchr.

=> "-happy-new-year"

Would WHEN be more 'proper' than IF in this case?
From: Kaz Kylheku
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <cf333042.0309301545.66c1d8d2@posting.google.com>
Pascal Costanza <········@web.de> wrote in message news:<············@newsreader2.netcologne.de>...
> Kaz Kylheku wrote:
> 
> > "DaveNlp" <(NOSPAM)·········@iol.it> wrote in message news:<··················@twister1.libero.it>...
> >>>(join '("happy" "new" "year") "-")
> >>>"happy-new-year"
> > 
> > 
> > This kind of repeated reduction of a sequence through a binary
> > operator is nicely handled functionally by REDUCE. Just take care of
> > the empty list case; REDUCE internally handles the case when the list
> > has length one:
> > 
> > (if wlist
> >   (reduce #'(lambda (x y)
> >               (concatenate 'string x sepchr y)) 
> >           wlist))
> > 
> > Apologies about the use of the implicit NIL result from IF. ;)
> 
> FWIW, I find the use of :initial-value clearer, as in:
> 
> (reduce (lambda (x y) (concatenate 'string x sepchr y))
>          wlist
>          :initial-value nil)
> 
> Then you don't have to handle the empty list.

But this screws up the processing for non-empty lists. The
:initial-value parameter is not useful in this situation, unless you
are prepared to handle the NIL value of X in the lambda and just
return Y. If you are going to do that, you can dispense with the
:INITIAL-VALUE and just make it handle two optional parameters
instead, checking the first one for NIL.

In effect, when you have :INITIAL-VALUE, it's as if that value was
added to the front of the sequence (or to the tail, if you have
:FROM-END T). So the list () is processed as (NIL) which returns NIL,
which is okay, but the list ("happy") is processed as (nil "happy")
which yields "-happy", and ("happy" "new") yields "-happy-new" and so
on. Always a troublesome dash at the beginning.

:INITIAL-VALUE works superbly when there is some idempotent element
that can be seeded into any length sequence with no ill effect. For
example, products and sums:

  (reduce #'my-mult product-list :initial-value 1)
  (reduce #'my-add term-list :initial-value 0)
From: Alan Crowe
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <86d6dgesu4.fsf@cawtech.freeserve.co.uk>
A potential problem with using reduce like this:

(defun join (wlist sepchr)
    (if wlist
	(reduce #'(lambda (x y)
		    (concatenate 'string x sepchr y)) 
		wlist)))

is that join then uses Schlemiel the painter's algorithm.
http://discuss.fogcreek.com/techInterview/default.asp?cmd=show&ixPost=153
Since concatenate's arguments are copied, the y argument to
the lambda expression is accumulating and repeatedly copying
the whole string. So if you have n strings of n characters,
the algorithm is order n cubed. DaveNlp's original join 

> (defun join (wlist sepchr)
>   (let ((string nil))
>     (dolist (sym wlist string)
>       (setf string
>         (concatenate 'string
>           string (if string sepchr nil) (string sym))))))

had the same problem, with string getting longer and longer
and getting copied again and again.

(defun join3 (word-list separator)
    (apply #'concatenate 'string
	   (first word-list)
	   (mapcan #'(lambda(x)(list separator x))
		   (rest word-list))))

seems to do the trick, running my test cases in n squared
time.

To my great surprise it handles the case of the empty word
list correctly as written. I think I've understood how that
has happened.

(car nil) => nil
(cdr nil) => nil
mapcan is cool about begin passed an empty list
(apply foo bar '()) turns into (funcall foo bar)
(concatenate 'string nil) => ""

That is the first time in 30 years of computer programming
that a computer has /voluntarily/ done what I wanted it to.
Isn't CL wonderful :-)

I don't know what to do about a really long list overflowing
the stack when apply tries to call concatenate on the list.
Thoughts anyone?

Alan Crowe
From: DaveNlp
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <nt0fb.4951$e6.159968@twister2.libero.it>
"Kaz Kylheku" <···@ashi.footprints.net> ha scritto nel messaggio

> This kind of repeated reduction of a sequence through a binary
> operator is nicely handled functionally by REDUCE. Just take care of
> the empty list case; REDUCE internally handles the case when the list
> has length one:
>
> (if wlist
>   (reduce #'(lambda (x y)
>               (concatenate 'string x sepchr y))
>           wlist))
>
> Apologies about the use of the implicit NIL result from IF. ;)

It was just the method that I looked for. :)
I have done a small modification to your idea
in manner that it works with numbers, symbols and lists.

(defun join-all (wlist sepchr)
    (if wlist
        (reduce #'(lambda (x y)
              (concatenate 'string
                  (if (numberp x) (princ-to-string x)
                      (if (listp x) (join x sepchr) (string x)))
                  sepchr
                  (if (numberp y) (princ-to-string y)
                      (if (listp y) (join y sepchr) (string y)))))
            wlist)))

>(setq mm (list "1" "2"))
>(join (list mm 'a 'b "ejz" 3.2) " ")
>"1 2 A B ejz 3.2"

Thx
DaveNlp
From: Christophe Turle
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <blbhj6$2q3$1@news.irisa.fr>
DaveNlp wrote:
> Does a similar function exists?
> 
> (defun join (wlist sepchr)
>   (let ((string nil))
>     (dolist (sym wlist string)
>       (setf string
>         (concatenate 'string
>           string (if string sepchr nil) (string sym))))))
> 
> 
>>(join '("happy" "new" "year") "-")
>>"happy-new-year"
> 

what about :

* (defun join (wlist sepchr)
    (reduce #'(lambda(s1 s2) (concatenate 'string s1 sepchr s2)) wlist ))

* (join '("happy" "new" "year") "-")

"happy-new-year"

--------------------------------------------------------------------

Christophe Turle
(format nil ···@~A.~A" 'turle 'wanadoo 'fr)
From: Michael Greenberg
Subject: Re: concatenate atoms into string
Date: 
Message-ID: <0pCeb.378$LJ5.14924@iad-read.news.verio.net>
(defun join (lst sep)
  (apply #'concatenate 'simple-string
         (cdr (mapcan #'(lambda (x)
                                   (list sep (string x)))
                      lst))))


"DaveNlp" <(NOSPAM)·········@iol.it> wrote in message
·······················@twister1.libero.it...
> Does a similar function exists?
>
> (defun join (wlist sepchr)
>   (let ((string nil))
>     (dolist (sym wlist string)
>       (setf string
>         (concatenate 'string
>           string (if string sepchr nil) (string sym))))))
>
> >(join '("happy" "new" "year") "-")
> >"happy-new-year"
>
> Thanks you.
> DaveNlp.
>
>