Suppose I want to create a nested looping structure that returned the list
((1 1) (1 2) (1 3) 1 (2 1) (2 2) (2 3) 2)
I tried doing
(loop for r from 1 to 2
collect (loop for c from 1 to 3 collect (list r c))
collect r)
but I end up with
(((1 1) (1 2) (1 3)) 1 ((2 1) (2 2) (2 3)) 2)
I also tried a loop like
(loop for r from 1 to 2
for c from 1 to 3
...)
but that didn't work either. What is it that I need to do? It all seems
a bit of a dark art.
Mark Carter wrote:
> Suppose I want to create a nested looping structure that returned the list
> ((1 1) (1 2) (1 3) 1 (2 1) (2 2) (2 3) 2)
>
> I tried doing
>
> (loop for r from 1 to 2
> collect (loop for c from 1 to 3 collect (list r c))
> collect r)
Hi,
Very close. Try append rather than the first collect.
Tayssir
········@gmail.com wrote:
> I like iterate as an alternative:
>
> (iter outer
> (for r from 1 to 2)
> (iter (for c from 1 to 3)
> (in outer (collect (list r c))))
> (collect r))
>
That is pretty damn cool.
But thinking like a teacher, I am concerned that the OP thought they
could (effectively):
(list '(a b) c) -> (a b c) ;; crazy!!!
Ok, what they actually wanted was:
(list '((1 2)(3 4)) 5) -> ((1 2)(3 4) 5) ;; crazy!!!
..but that is the same thing.
Didactically speaking, methinks one wants more to get folks to
understand that Lisp does not and should not and really cannot guess
what we want. Fact is:
(list x y) -> (x y)
Therefore (list '(1 2) 3) -> ((1 2) 3). Any lisp behaving:
(list '(1 2) 3) -> (1 2 3)
...is so broken as to be unprogrammable. The Op wants that behavior, but
someday they will (list (1 2) 3) and want ((1 2) 3). They are dead,
their Lisp will give them what it thinks they want, (1 2 3).
(iterate ... (in <xx> (collect...)))
Is a nice way to do nconc, but the OP should undersatnd that vital
difference between nconc and list.
I am not sure that "(in xxx (collect .....))" conveys that.
ken
Kenny Tilton wrote:
> But thinking like a teacher, I am concerned that the OP thought they
> could (effectively):
>
> (list '(a b) c) -> (a b c) ;; crazy!!!
>
> Ok, what they actually wanted was:
>
> (list '((1 2)(3 4)) 5) -> ((1 2)(3 4) 5) ;; crazy!!!
>
> ..but that is the same thing.
>
> Didactically speaking, methinks one wants more to get folks to
> understand that Lisp does not and should not and really cannot guess
> what we want.
I have to admit, it took me a while to grok the difference between
append/collect and mapcan/mapcar, particularly in recursive processes.
Essentially, the way I learned it was to gain the intuition first from
trial & error, then more intellectually later.
(I think John Dewey may have said something interesting about this sort
of education.)
Maybe using TRACE for mapcan/mapcar and printing named accumulation
variables (with loop) might help. I was impressed yesterday by the
metaobject protocol tutorials by Manuel Odendahl because it seemed to
be the only tutorial-type thing for the mop using DESCRIBE and TRACE.
http://wiki.alu.org/Metaobject_Protocol
Perhaps loop needs a trace facility.
Tayssir
Kenny Tilton wrote:
> But thinking like a teacher, I am concerned that the OP thought they
> could (effectively):
What I was actually doing is that I had a matrix, represented as a flat
list. The operation I was attempting to perform was to add a column to
the end of the matrix. Here's the code I eventually came up with:
(defun add-col ()
(when (< *cols* *max-cols*)
(let ((new-grid
(loop for r from 1 to *rows*
append (loop for c from 1 to *cols*
collect (rc r c))
collect #\Space)))
(setq *grid* new-grid))
(inc! *cols*)))
Thanks go to the poster who recommended changing collect to append. I
had simplified the problem when I presented it to this newsgroup. One of
the problems as a noob to lisp is that there is a smorgasbord of things
to choose from, and it can be difficult to discern which thing one
wants, and exactly how it is supposed to operate.
The "append" statement gets the original row, whilst the "collect"
statement tacks on an additional character (it's a matrix of characters
rather than numbers).
So, "job's a good'un", as they say up North.
Mark Carter wrote:
> Kenny Tilton wrote:
>
>> But thinking like a teacher, I am concerned that the OP thought they
>> could (effectively):
>
>
> What I was actually doing is that I had a matrix, represented as a flat
> list.
That is a pretty scary sentence. Why not represent a matrix as a matrix?
> The operation I was attempting to perform was to add a column to
> the end of the matrix. Here's the code I eventually came up with:
> (defun add-col ()
> (when (< *cols* *max-cols*)
> (let ((new-grid
> (loop for r from 1 to *rows*
> append (loop for c from 1 to *cols*
> collect (rc r c))
> collect #\Space)))
> (setq *grid* new-grid))
> (inc! *cols*)))
>
> Thanks go to the poster who recommended changing collect to append.
What was wrong with my suggestion of NCONC? :)
My feelings are not hurt, this is a hint about a big Lisp learning
issue: one needs to know when one can use destructive operations. It may
not matter in this case, but as one of our old sayings goes, "It does
not cost any more to do it right."
> I
> had simplified the problem when I presented it to this newsgroup. One of
> the problems as a noob to lisp is that there is a smorgasbord of things
> to choose from, and it can be difficult to discern which thing one
> wants, and exactly how it is supposed to operate.
Yep. Ten years now heads-down use and I am still learning.
>
> The "append" statement gets the original row, whilst the "collect"
> statement tacks on an additional character (it's a matrix of characters
> rather than numbers).
>
> So, "job's a good'un", as they say up North.
Not so sure. I am /really/ worried about you tossing a dimension of your
conceptual data structure in representing it.
kenny
Kenny Tilton wrote:
> Not so sure. I am /really/ worried about you tossing a dimension of your
> conceptual data structure in representing it.
Hmm, I suppose a list of "cells" would be an interesting choice.
I am even toying with the idea of ditching the flexibility to add rows
and columns. I can then eliminate code, making the program shorter.
Mark Carter wrote:
> Suppose I want to create a nested looping structure that returned the list
> ((1 1) (1 2) (1 3) 1 (2 1) (2 2) (2 3) 2)
>
> I tried doing
>
> (loop for r from 1 to 2
> collect (loop for c from 1 to 3 collect (list r c))
> collect r)
>
> but I end up with
>
> (((1 1) (1 2) (1 3)) 1 ((2 1) (2 2) (2 3)) 2)
>
> I also tried a loop like
>
> (loop for r from 1 to 2
> for c from 1 to 3
> ...)
>
> but that didn't work either. What is it that I need to do?
(loop for r from 1 to 2
nconc (loop for c from 1 to 3 collect (list r c))
collect r)
> It all seems
> a bit of a dark art.
No it doesn't. :) You just have to slow down and notice that in your
first try you were collecting /lists/ of pairs, so naturally the result
included the collected pairs each set in their own list.
Your desired result is a bit odd. You want the lists of pairs spliced
into the result, ie, you want the toplevel list in which you are
generating the pairs (your inner loop/collect) to go away.
We use things like nconc and mapcan for that.
kenny