From: Carla
Subject: File I/O & String conversion - CLISP
Date: 
Message-ID: <e75ba66b-7a22-4971-bc76-e122316ca360@k7g2000hsd.googlegroups.com>
Hi.
I have a txt file containing a combination of D/./*/F/1 characters. In
the example below, the first row has 5 elements D, ., *, ., F and
second row also has 5 elements ., ., ., ., .

D.*.F
..1..

I have to read this data line by line, and convert it into list of
lists, of individual strings.

(("D" "." *" "." "F") ("." "." "1" "." "."))

Can someone help me out with this please?

From: Rob Warnock
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <U9Wdnfq3JtOcpGDVnZ2dnUVZ_vCdnZ2d@speakeasy.net>
Carla  <················@gmail.com> wrote:
+---------------
| D.*.F
| ..1..
| 
| I have to read this data line by line, and convert it into list of
| lists, of individual strings.
| 
| (("D" "." *" "." "F") ("." "." "1" "." "."))
+---------------

LOOP, READ-LINE, and STRING are your friends. It's almost a "one-liner".

[O.k., depending on how fanatical you are about formatting, it's
actually a 2- or 3-liner. But it still took less than 40 seconds
by the stopwatch to write & test a solution that works with your
sample input data set.]

Note: It's considered polite in this list to first show us us your
best efforts so far [the code you wrote], and the problems you have
experienced [the exact error messages]. rather than just starting off
with "Do my homework for me!".


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Carla
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <754c71ee-919e-437b-aa64-d8fca3de7c32@64g2000hsm.googlegroups.com>
I am trying with this version of my function.

(let ((in (open "file1.txt" :if-does-not-exist nil))
      (main-list nil))
  (when in
    (loop for line = (read-line in nil)
       while line do (let ((line-string line)
			   (string-form nil))
		       (loop for i from 1 to (length line-string)
			  do
			    (push (subseq line-string (1- i) i) string-form))
		       (push string-form main-list)))
    (close in)) (return main-list))

But this is just returning true, even after I am explicitly returning
main-list before the end of let block.
From: Jason
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <ae83e9b7-46bf-4ccf-b68e-fcdd17626d75@q26g2000prq.googlegroups.com>
On Oct 20, 8:29 pm, Carla <················@gmail.com> wrote:
> I am trying with this version of my function.
>
> (let ((in (open "file1.txt" :if-does-not-exist nil))
>       (main-list nil))
>   (when in
>     (loop for line = (read-line in nil)
>        while line do (let ((line-string line)
>                            (string-form nil))
>                        (loop for i from 1 to (length line-string)
>                           do
>                             (push (subseq line-string (1- i) i) string-form))
>                        (push string-form main-list)))
>     (close in)) (return main-list))
>
> But this is just returning true, even after I am explicitly returning
> main-list before the end of let block.

I changed the (return main-list) to simply return-list, and prefaced
your push statements with nreverse, and the code works as expected.

(let ((in (open "file1.txt" :if-does-not-exist nil))
      (main-list nil))
  (when in
    (loop for line = (read-line in nil)
       while line do (let ((line-string line)
			   (string-form nil))
		       (loop for i from 1 to (length line-string)
			  do
			  (push (subseq line-string (1- i) i)
				string-form))
		       (push (nreverse string-form) main-list)))
    (close in))
  (nreverse main-list))

-Jason
From: Rob Warnock
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <_uednXGU2pWrAWDVnZ2dnUVZ_iydnZ2d@speakeasy.net>
Jason  <·······@gmail.com> wrote:
+---------------
| Carla <················@gmail.com> wrote:
| > I am trying with this version of my function.
...[trimmed]...
| > But this is just returning true, even after I am explicitly returning
| > main-list before the end of let block.
| 
| I changed the (return main-list) to simply return-list, and prefaced
| your push statements with nreverse, and the code works as expected.
| 
| (let ((in (open "file1.txt" :if-does-not-exist nil))
|       (main-list nil))
|   (when in
|     (loop for line = (read-line in nil)
|        while line do (let ((line-string line)
| 			   (string-form nil))
| 		       (loop for i from 1 to (length line-string)
| 			  do
| 			  (push (subseq line-string (1- i) i)
| 				string-form))
| 		       (push (nreverse string-form) main-list)))
|     (close in))
|   (nreverse main-list))
+---------------

Carla, now that Jason has debugged the proximate problem, we can
start working on style and using common CL idioms, especially
within the LOOPs.

First, there's a standard CL macro that takes care of opening and
closing a file for you, so instead of:

    (let ((in (open "file1.txt" :if-does-not-exist nil)))
      (let ((main-list nil))
	(when in
	  ...{body which PUSHes onto MAIN-LIST}...)
	(close in))
      main-list)

you can write this:

    (with-open-file (in "file1.txt" :if-does-not-exist nil)
      (let ((main-list nil))
        ...{body}...
        main-list))

Next, you can eliminate the LINE-STRING variable -- just use LINE,
it's still in scope.

Your LOOPs just *cry* out for using the COLLECT feature of the
LOOP macro instead of setting up results variables (MAIN-LIST,
STRING-FORM) and PUSH'ing stuff onto them. Plus, COLLECT keeps
things in forward order so you don't have to REVERSE (or NREVERSE)
them. First let's do the outer LOOP:

    (with-open-file (in "file1.txt" :if-does-not-exist nil)
      (loop for line = (read-line in nil)
	    while line
	 collect (let ((string-form nil))
		   (loop for i from 1 to (length line) do
		     (push (subseq line (1- i) i) string-form))
		   string-form)))

and now the inner:

    (with-open-file (in "file1.txt" :if-does-not-exist nil)
      (loop for line = (read-line in nil)
	    while line
	 collect (loop for i from 1 to (length line)
		   collect (subseq line (1- i) i))))

Finally, you can use the FOR...ACROSS array scanning feature
of LOOP to walk each LINE character by character, with STRING
to turn each character back into a string:

    (with-open-file (in "file1.txt" :if-does-not-exist nil)
      (loop for line = (read-line in nil)
	    while line
	 collect (loop for c across line collect (string c))))

And there's the 3-line solution I mentioned before
[well, 4 lines, with the addition of the WITH-OPEN-FILE].


-Rob

p.s. People differ it how much they like to compress vertical
whitespace. You can crunch the above to 3 lines this way:

    (with-open-file (in "file1.txt" :if-does-not-exist nil)
      (loop for line = (read-line in nil) while line
	 collect (loop for c across line collect (string c))))

though many people prefer a looser layout that's more easily
parsable by eye [and looks like the other LOOPs you're likely
to find in CL code]:

    (with-open-file (in "file1.txt" :if-does-not-exist nil)
      (loop for line = (read-line in nil)
	    while line
	 collect (loop for c across line
		   collect (string c))))

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Dimiter "malkia" Stanev
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <gdl550$18u$1@registered.motzarella.org>
Thanks, Rob!

That was a good lesson in refactoring for me, and I'm sure Carla would 
appreciate it too!

Rob Warnock wrote:
> Jason  <·······@gmail.com> wrote:
> +---------------
> | Carla <················@gmail.com> wrote:
> | > I am trying with this version of my function.
> ....[trimmed]...
> | > But this is just returning true, even after I am explicitly returning
> | > main-list before the end of let block.
> | 
> | I changed the (return main-list) to simply return-list, and prefaced
> | your push statements with nreverse, and the code works as expected.
> | 
> | (let ((in (open "file1.txt" :if-does-not-exist nil))
> |       (main-list nil))
> |   (when in
> |     (loop for line = (read-line in nil)
> |        while line do (let ((line-string line)
> | 			   (string-form nil))
> | 		       (loop for i from 1 to (length line-string)
> | 			  do
> | 			  (push (subseq line-string (1- i) i)
> | 				string-form))
> | 		       (push (nreverse string-form) main-list)))
> |     (close in))
> |   (nreverse main-list))
> +---------------
> 
> Carla, now that Jason has debugged the proximate problem, we can
> start working on style and using common CL idioms, especially
> within the LOOPs.
> 
> First, there's a standard CL macro that takes care of opening and
> closing a file for you, so instead of:
> 
>     (let ((in (open "file1.txt" :if-does-not-exist nil)))
>       (let ((main-list nil))
> 	(when in
> 	  ...{body which PUSHes onto MAIN-LIST}...)
> 	(close in))
>       main-list)
> 
> you can write this:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (let ((main-list nil))
>         ...{body}...
>         main-list))
> 
> Next, you can eliminate the LINE-STRING variable -- just use LINE,
> it's still in scope.
> 
> Your LOOPs just *cry* out for using the COLLECT feature of the
> LOOP macro instead of setting up results variables (MAIN-LIST,
> STRING-FORM) and PUSH'ing stuff onto them. Plus, COLLECT keeps
> things in forward order so you don't have to REVERSE (or NREVERSE)
> them. First let's do the outer LOOP:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (loop for line = (read-line in nil)
> 	    while line
> 	 collect (let ((string-form nil))
> 		   (loop for i from 1 to (length line) do
> 		     (push (subseq line (1- i) i) string-form))
> 		   string-form)))
> 
> and now the inner:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (loop for line = (read-line in nil)
> 	    while line
> 	 collect (loop for i from 1 to (length line)
> 		   collect (subseq line (1- i) i))))
> 
> Finally, you can use the FOR...ACROSS array scanning feature
> of LOOP to walk each LINE character by character, with STRING
> to turn each character back into a string:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (loop for line = (read-line in nil)
> 	    while line
> 	 collect (loop for c across line collect (string c))))
> 
> And there's the 3-line solution I mentioned before
> [well, 4 lines, with the addition of the WITH-OPEN-FILE].
> 
> 
> -Rob
> 
> p.s. People differ it how much they like to compress vertical
> whitespace. You can crunch the above to 3 lines this way:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (loop for line = (read-line in nil) while line
> 	 collect (loop for c across line collect (string c))))
> 
> though many people prefer a looser layout that's more easily
> parsable by eye [and looks like the other LOOPs you're likely
> to find in CL code]:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (loop for line = (read-line in nil)
> 	    while line
> 	 collect (loop for c across line
> 		   collect (string c))))
> 
> -----
> Rob Warnock			<····@rpw3.org>
> 627 26th Avenue			<URL:http://rpw3.org/>
> San Mateo, CA 94403		(650)572-2607
> 
From: Stelian Ionescu
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <pan.2008.10.22.00.41.39@common-lisp.net>
On Tue, 21 Oct 2008 04:09:10 -0500, Rob Warnock wrote:
[snip]
> p.s. People differ it how much they like to compress vertical
> whitespace. You can crunch the above to 3 lines this way:
> 
>     (with-open-file (in "file1.txt" :if-does-not-exist nil)
>       (loop for line = (read-line in nil) while line
> 	 collect (loop for c across line collect (string c))))

or even simpler:

     (with-open-file (in "file1.txt" :if-does-not-exist nil)
       (loop for line = (read-line in nil) while line
 	 collect (map 'list #'string line)))

-- 
Stelian Ionescu a.k.a. fe[nl]ix
Quidquid latine dictum sit, altum videtur.
From: William James
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <3249e993-1914-4a99-a12f-b68062c5bb45@v30g2000hsa.googlegroups.com>
On Oct 20, 7:23 pm, Carla <················@gmail.com> wrote:
> Hi.
> I have a txt file containing a combination of D/./*/F/1 characters. In
> the example below, the first row has 5 elements D, ., *, ., F and
> second row also has 5 elements ., ., ., ., .
>
> D.*.F
> ..1..
>
> I have to read this data line by line, and convert it into list of
> lists, of individual strings.
>
> (("D" "." *" "." "F") ("." "." "1" "." "."))
>
> Can someone help me out with this please?

Ruby:

IO.readlines("junk0").map{|line| line.strip.split("") }
From: Marco Antoniotti
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <e828788f-3d27-4ce2-8ef8-0d9e126704f4@a70g2000hsh.googlegroups.com>
On Oct 22, 10:01 pm, William James <·········@yahoo.com> wrote:
> On Oct 20, 7:23 pm, Carla <················@gmail.com> wrote:
>
> > Hi.
> > I have a txt file containing a combination of D/./*/F/1 characters. In
> > the example below, the first row has 5 elements D, ., *, ., F and
> > second row also has 5 elements ., ., ., ., .
>
> > D.*.F
> > ..1..
>
> > I have to read this data line by line, and convert it into list of
> > lists, of individual strings.
>
> > (("D" "." *" "." "F") ("." "." "1" "." "."))
>
> > Can someone help me out with this please?
>
> Ruby:
>
> IO.readlines("junk0").map{|line| line.strip.split("") }

(defun process-file (file)
   (mapcar (lambda (line) (split-sequence line)) (readlines file)))

(compile 'process-file)

Now, which part of the Ruby code is not rendered in CL?

Cheers
--
Marco
From: Pascal Bourguignon
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <48ffa33e$0$12213$426a74cc@news.free.fr>
Marco Antoniotti wrote:
> On Oct 22, 10:01 pm, William James <·········@yahoo.com> wrote:
>> On Oct 20, 7:23 pm, Carla <················@gmail.com> wrote:
>>
>>> Hi.
>>> I have a txt file containing a combination of D/./*/F/1 characters. In
>>> the example below, the first row has 5 elements D, ., *, ., F and
>>> second row also has 5 elements ., ., ., ., .
>>> D.*.F
>>> ..1..
>>> I have to read this data line by line, and convert it into list of
>>> lists, of individual strings.
>>> (("D" "." *" "." "F") ("." "." "1" "." "."))
>>> Can someone help me out with this please?
>> Ruby:
>>
>> IO.readlines("junk0").map{|line| line.strip.split("") }
> 
> (defun process-file (file)
>    (mapcar (lambda (line) (split-sequence line)) (readlines file)))
> 
> (compile 'process-file)
> 
> Now, which part of the Ruby code is not rendered in CL?

No, which part of CL code is not rendered in Ruby?

;-)


-- 
__Pascal Bourguignon__
http://www.informatimago.com
From: Rob Warnock
Subject: Re: File I/O & String conversion - CLISP
Date: 
Message-ID: <_fOdnVvztLiKyZ3UnZ2dnUVZ_tLinZ2d@speakeasy.net>
Pascal Bourguignon  <···@informatimago.com> wrote:
+---------------
| Marco Antoniotti wrote:
| > On Oct 22, 10:01 pm, William James <·········@yahoo.com> wrote:
| >> On Oct 20, 7:23 pm, Carla <················@gmail.com> wrote:
| >>> I have to read this data line by line, and convert it into list of
| >>> lists, of individual strings.
| >>> (("D" "." *" "." "F") ("." "." "1" "." "."))
| >>> Can someone help me out with this please?
| >> Ruby:
| >>
| >> IO.readlines("junk0").map{|line| line.strip.split("") }
| > 
| > (defun process-file (file)
| >    (mapcar (lambda (line) (split-sequence line)) (readlines file)))
| > 
| > (compile 'process-file)
| > 
| > Now, which part of the Ruby code is not rendered in CL?
| 
| No, which part of CL code is not rendered in Ruby?
| 
| ;-)
+---------------

COMPILE, of course!  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607