From: Tayssir John Gabbour on
On Jan 30, 4:23 pm, Tayssir John Gabbour <tayssir.j...(a)googlemail.com>
wrote:
> While I'm a big LOOP partisan, I think REDUCE is just more
> streamlined, perhaps clearer than LOOP.

Hmm, I take that back; some of the ones where you're modifying lists
while iterating over them are pretty concise and clear.


All the best,
Tayssir
From: Raymond Wiker on
Huai Yuan <huaiyuan(a)gmail.com> writes:

> Adam White <spudboy(a)iinet.net.au> writes:
>> 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")
> [...]
>
> (defun concatenate-adjacent-strings (list)
> (reduce (lambda (x y)
> (if (and (stringp x) (stringp (car y)))
> (cons (concatenate 'string x (car y)) (cdr y))
> (cons x y)))
> list :from-end t :initial-value nil))

I wish I'd been able to think up something like this :-)
From: Tayssir John Gabbour on
On Jan 30, 5:26 pm, Tayssir John Gabbour <tayssir.j...(a)googlemail.com>
wrote:
> > While I'm a big LOOP partisan, I think REDUCE is just more
> > streamlined, perhaps clearer than LOOP.
>
> Hmm, I take that back; some of the ones where you're modifying lists
> while iterating over them are pretty concise and clear.

Bothered that the LOOP versions are shorter than the relative
monstrosity I created, I looked for more impressive higher-order
function stuff to cut down on size:

(defn concatenate-adjacent-strings [lst]
(lazy-seq
(cond (empty? lst)
nil
(string? (first lst))
(let [[strings remainder] (split-with string? lst)]
(cons (apply str strings) (concatenate-adjacent-strings
remainder)))
:else
(cons (first lst) (concatenate-adjacent-strings (rest
lst))))))

Ssomeone more familiar with lazy eval than me can probably translate
this into idiomatic CL, and compare it to the succinct LOOP versions.


All the best,
Tayssir
From: Kaz Kylheku on
On 2010-01-30, Ole Arndt <ole(a)sugarshark.com> wrote:
> Richard Fateman <fateman(a)cs.berkeley.edu> writes:
>
>> (defun f(lis)
>> (let ((h (first lis))(r (rest lis)))
>> (cond ((and(stringp h)(stringp (first r)))
>> (f (cons (concatenate 'string h (first r))
>> (rest r))))
>> (r (cons h (f r)))
>> (t lis))))
>
> Much nicer, but not tail recursive anymore ;)

Don't forget that we can rewrite tail recursion into proper iteration
with a macro, which preserves the tail recursive expression.

Search the archives for the TAILPROG macro.
From: W. James on
W. James wrote:

> Ole Arndt wrote:
>
> > Adam White <spudboy(a)iinet.net.au> writes:
> >
> > > 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")
> > >
> > > My first solution which works, but is as ugly as sin is:
> > >
> > > (loop
> > > with curr = ""
> > > with save = '()
> > > for p in '("1" "2" 3 4 "5" "6" 7 8 "9") do
> > > (cond
> > > ((stringp p) (setf curr (concatenate 'string curr p)))
> > > ((equal curr "") (push p save))
> > > (t (push curr save) (push p save) (setf curr "")))
> > > finally (return (nreverse (cons curr save))))
> > >
> > > Surely there has got to be a better way to do this!
> > >
> > > Any pointers?
> >
> > And another solution:
> >
> > (defun merge-strings (list)
> > (labels ((conc (beg cur rest)
> > (cond ((null cur)
> > beg)
> > ((and (stringp cur) (stringp (first rest)))
> > (conc beg
> > (concatenate 'string cur (first rest))
> > (rest rest)))
> > (t
> > (conc (nconc beg (list cur))
> > (first rest)
> > (rest rest))))))
> > (conc nil (first list) (rest list))))
>
> CL (COBOL-LISP) isn't very good at handling lists. You've illustrated
> that very well.
> 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"]

A little golfing:

["1","2",3,4,"5","6",7,8,"9"].reduce([]){|a,x|
(x.is_a?(String) && a[-1].is_a?(String) ? a[-1] : a ) << x
a}
==>["12", 3, 4, "56", 7, 8, "9"]

--