This post is about reading the file and give a format list.We can see from this post that the LOOP is very powerful.
Q:
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..
read this data line by line, and convert it into list of lists, of individual strings.
(("D" "." *" "." "F") ("." "." "1" "." "."))
Solution:
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
No comments:
Post a Comment