From: Frode V. Fjeld on
tar(a)sevak.isi.edu (Thomas A. Russ) writes:

> (defun f(l)
> (cond ((null l) nil)
> ((and (stringp (car l))(stringp (cadr l)))
> (f (cons (concatenate 'string (car l) (cadr l))
> (cddr l))))
> ((cadr l) (cons (car l)(f (cdr l))))
> (t l)))

Doesn't this break if the list contains a NIL element? I guess the cadr
should be a cdr.

This is of course a very subjective issue, but I'm surprised that
apparently so many programmers find it attractive to write trivial
iterations in so many .. well, strange ways. I think the loop example I
gave before is pretty much superior to all the other examples provided
in this thread in the sense that it's easy to see what it does
(correctly), and it's easy to see that it has perfect O(N) behavior both
in terms of the number of list elements, the string lengths, and number
of consecutive strings:

(defun f (list)
(loop while list
collect (if (not (stringp (car list)))
(pop list)
(with-output-to-string (s)
(loop while list
while (stringp (car list))
do (write-string (pop list) s))))))

--
Frode V. Fjeld
From: Adam White on
On 02/03/2010 09:27 AM, Tayssir John Gabbour wrote:

[snippity doo dah]

> Maybe the original poster is writing a tokenizer, and nil
> represents some kinda null object.

Actually there aren't supposed to be any '()s in the input stream.
There are only supposed to be sublists representing actors
(nominative, accusative, dative, genitive, verbs), four value tuples
representing RGBA colours, and strings for verbatim text.

The intended purpose is an english-grammar state machine. Given a
list of strings and other items in a list, the state machine
turns tokens into an english string.

The adjacent string concatenation is just an optimisation hack for
rendering.

A
From: Pillsy on
On Feb 3, 3:49 am, "Frode V. Fjeld" <fr...(a)netfonds.no> wrote:
> t...(a)sevak.isi.edu (Thomas A. Russ) writes:
>
> > (defun f(l)
> >    (cond ((null l) nil)
> >     ((and (stringp (car l))(stringp (cadr l)))
> >           (f  (cons (concatenate 'string (car l) (cadr l))
> >                     (cddr l))))
> >    ((cadr l) (cons (car l)(f (cdr l))))
> >    (t l)))
>
> Doesn't this break if the list contains a NIL element? I guess the cadr
> should be a cdr.
>
> This is of course a very subjective issue, but I'm surprised that
> apparently so many programmers find it attractive to write trivial
> iterations in so many .. well, strange ways.

I find it surprising too, and it's especially surprising that no one's
used the one alternative strategy that would, IMO, actually have
comparable clarity, which is to use *two* mutually recursing
functions. The problem can be easily handled by a simple finite state
machine, and mutually recursing functions are a good, obvious way to
implement finite state machines. Put them inside a LABELS form and you
can use Kaz's TAILPROG macro if your implementation won't merge the
tail calls for some reason.

> I think the loop example I
> gave before is pretty much superior to all the other examples provided
> in this thread in the sense that it's easy to see what it does
> (correctly), and it's easy to see that it has perfect O(N) behavior both
> in terms of the number of list elements, the string lengths, and number
> of consecutive strings:
>
>   (defun f (list)
>     (loop while list
>           collect (if (not (stringp (car list)))
>                       (pop list)
>                       (with-output-to-string (s)
>                         (loop while list
>                               while (stringp (car list))
>                               do (write-string (pop list) s))))))

I agree. I also think it's better than the obvious mutually recursing
solution, but the disparity isn't as glaring.

(defun merge-strings (list)
(labels ((normal (list acc)
(if (null list)
(nreverse acc)
(destructuring-bind (f . r) list
(if (stringp f)
(string-run r acc (list f))
(normal r (cons f acc))))))
(string-run (list acc sacc)
(let ((f (first list)))
(if (stringp f)
(string-run (rest list) acc (cons f sacc))
(normal list
(cons (apply #'concatenate 'string
(nreverse sacc))
acc))))))
(normal list '())))

It would even work in Scheme, unlike the alleged Scheme solution
posted in the thread, though you might have to write the moral
equivalent of CONCATENATE for strings yourself.

Cheers,
Pillsy
From: André Thieme on
Am 29.01.2010 19:23, schrieb W. James:

> Let's use Matzlisp:
>
> ["1","2",3,4,"5","6",7,8,"9"].inject([]){|a,x|
> (if x.is_a?(String) and a.last.is_a?(String)
> a.last
> else
> a
> end)<< x
> a
> }
> ==>["12", 3, 4, "56", 7, 8, "9"]

OMG, is Ruby really that complicated? William, you should try it in Lisp:
(mapcat #(if (string? (first %)) [(apply str %)] %)
(partition-by string? ["1" "2" 3 4 "5" "6" 7 8 "9"]))


André
--
Lisp is not dead. It's just the URL that has changed:
http://clojure.org/
From: Wade on
On Jan 29, 7:56 am, Adam White <spud...(a)iinet.net.au> wrote:
> Given a mixed list of strings and other items, I'd like to concatenate
> all strings (and only strings) adjacent to each other.
>
> So for '("1" "2" 3 4 "5" "6" 7 8 "9"), we should return
>
> ("12" 3 4 "56" 7 8 "9")
>

Saturday is play day...

(defun concatas (list &aux result)
(dolist (element list (nreverse result))
(if (and (stringp element) (stringp (car result)))
(setf (car result) (concatenate 'string (car result) element))
(push element result))))

CL-USER> (concatas '("1" "2" 3 4 "5" "6" 7 8 "9"))
("12" 3 4 "56" 7 8 "9")
CL-USER>

Wade