This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Reading In text file.

21 posts · 4210 views

Hi All im new to the site. Having a bit of a problem, im pretty new to lisp but I've been trying to learn it just as something to experiment with for fun :)


Anyways Im trying to figure out how to read in data and store it as kinda a global parameter.

Like for instance (dunno if I can do this)
(defparameter *imalist* (list))
So that would define a blank list

and then I would read data from "mydata.txt"
which contains various numbers.

I found something on google, but it didnt actually store the data in anything. I'd prefer to store it in a list.....but everything i've found doesn't keep it in a variable.
then I can do stuff with *imalist* but now after I read in the data *imalist* would be a list with a bunch of numbers in it. Then Im gonna do some math calculations on the list (but thats for another day) the main problem I have right now is Storing them into a list (because I have the function done that calculates the average of the *imalist* right now)

Appreciate everyones help

Re: Reading In text file.

To change the value of a variable, use setf. Like this:
(defun read-integers-from-file (file)
  ;; reads file and returns a list with the integers inside it
  ...)

(defparameter *imalist* (list))

(setf *imalist* (read-integers-from-file "/path/to/mydata.txt"))

Re: Reading In text file.

Or a little more advanced, you can use LET on special variables:
;;Defvar or defparameter *imalist* somewhere before
(let ((*imalist* (read-integers-from-file "/path/to/mydata.txt")))
  (function-depending-on-imalist)) ;Depends on the one as set
(function-depending-on-imalist) ;Doesn't depend on as set, outside that LET
It kindah sneaks in the special variable as argument where-ever it is needed.(So it is useful when you find yourself entering an argument unchanged all the time.) I am starting to like that feature as much as macros :).

Re: Reading In text file.

gugamilare wrote:To change the value of a variable, use setf. Like this:
(defun read-integers-from-file (file)
  ;; reads file and returns a list with the integers inside it
  ...)

(defparameter *imalist* (list))

(setf *imalist* (read-integers-from-file "/path/to/mydata.txt"))
Oh ok that makes sense.
in the read-integers-from-file. what would I need to do to make sure it "stays" a global parameter
would something like THIS work
(let ((in (open "data.txt" :if-does-not-exist nil)))
  (when in
    (loop for line = (read-line in nil)
         while line do (format t "~a~%" line))
    (close in)))
then have
(defparameter *imalist* (list))

(setf *imalist* (read-integers-from-file "/path/to/mydata.txt")
like after that?
remember im new :)

Re: Reading In text file.

Sorry, I didn't quite understand what you are trying to do. If you declare
(defparameter *imalist* (list))
then *imalist* will still be a global variable no matter how many times you change its value using setf or let (like in Jasper's example). Or maybe what you want is not to change its value? In this case all you need to do is not to use setf and always use non-destructive functions when operating with your variable.

To know if a function is destructive, look at its documentation. For example, comparing delete and remove:
cl-user> (documentation 'delete 'function)
"Return a sequence formed by destructively removing the specified ITEM from
  the given SEQUENCE."
cl-user> (documentation 'remove 'function)
"Return a copy of SEQUENCE with elements satisfying the test (default is
   EQL) with ITEM removed."
they do the same thing, but delete is destructive while remove is not.

Re: Reading In text file.

Ok basically here is what Im trying to do.

I have a global parameter *mylist* that defines a list (like 1 3 5 6 3 1) etc...

Right now Im just using that as an example.

What I want to do is read in a text file (which consists of JUST integers) into the global parameter *mylist*. thats all I need to do.

So after the readin function, *mylist* will contain the numbers from the text file (if that makes sense)
the text file just has a bunch of integers in it

This code u listed above i think would work. except I dont know what goes in the "..." part. because this is my first time with lisp
(defun read-integers-from-file (file)
  ;; reads file and returns a list with the integers inside it
  ...)

(defparameter *imalist* (list))

(setf *imalist* (read-integers-from-file "/path/to/mydata.txt"))

Re: Reading In text file.

Mercenary85 wrote:Ok basically here is what Im trying to do.

I have a global parameter *mylist* that defines a list (like 1 3 5 6 3 1) etc...

Right now Im just using that as an example.

What I want to do is read in a text file (which consists of JUST integers) into the global parameter *mylist*. thats all I need to do.

So after the readin function, *mylist* will contain the numbers from the text file (if that makes sense)
the text file just has a bunch of integers in it
Ok, so you are asking if *mylist* will "forget" its previous value and contain a list with only the numbers from the text file? Yes, that is what the code will do.
Mercenary85 wrote:This code u listed above i think would work. except I dont know what goes in the "..." part. because this is my first time with lisp
It seems you have a text file? You need the macro with-open-file and the function read. An example how it is supposed to do. If "data.txt" contains
23 42 25
Then
cl-user> (with-open-file (data "/home/gugamilare/data.txt")
           (format t "The first integer is ~A~%" (read data nil :eof))
           (format t "The second integer is ~A~%" (read data nil :eof))
           (format t "The third integer is ~A~%" (read data nil :eof))
           (format t "No more numbers in the file!~%The value returned by (read data nil :eof) is ~S~%"
                   (read data nil :eof)))
The first integer is 23
The second integer is 42
The third integer is 25
No more numbers in the file!
The value returned by (read data nil :eof) is :eof
nil
This is just an example, you will need to put this in a loop.

Re: Reading In text file.

Mercenary85 wrote:except I dont know what goes in the "..." part. because this is my first time with lisp
In the vein of teaching to fish rather than giving fish: try use WITH-OPEN-FILE to open a file (could also just OPEN and CLOSE yourself) with READ, check they're numbers with NUMBERP then you could collect that into a list with LOOP like here, but with (prompt ..) replaced.

Re: Reading In text file.

I understand the readin part. but I still dont see how that puts it into the global variable *mylist*?

Like if I define *mylist* as a parameter list thats blank.

then I read in the numbers from data.txt
and data.txt contains (5 6 7 1 5 12 6 7)

then after I readin. I want *mylist* (the global variable) to contain (5 6 7 1 5 12 6 7) and never lose those values (until i decide to change them)
would something like this work
(defun read-setup (thefile)
(with-open-file (stream thefile)
    (loop for line = (read stream nil 'end)
          until (eq line 'end)           
          do (print (list (coerce line 'integer) ;want to make single list
                            )     
              )     
     )
)
)
then have this?
(defparameter *imalist* (list))

(setf *imalist* (read-integers-from-file "/path/to/mydata.txt"))
would that store the integers into the global variable list *imalist*

Re: Reading In text file.

Yes. (setf x y) stores y into the place currently known as x.

Re: Reading In text file.

nuntius wrote:Yes. (setf x y) stores y into the place currently known as x.
So my above code should work then?

a buddy of mine suggested these
(setf example-list (read-file "data.txt"))
(loop for data in example-list do
   (setf ternary-tree (insert data ternary-tree))
)


(defun read-file (file-name)
 (setf file-stream (open file-name :if-does-not-exist nil))
  (setf file-data (read file-stream))
 file-data
)
as 2 possible ones. but he doesn't know lisp "that" well so i was unsure.

edit: ok i tried doing that. It printed out the list correctly...but still didnt hold the value for *imalist*
There has to be an easy way to do this I know, im just missing it

Re: Reading In text file.

Mercenary85 wrote:
nuntius wrote:Yes. (setf x y) stores y into the place currently known as x.
So my above code should work then?
The code you created is very close to a solution, don't give up yet ;). But, unfortunately, it does not do anything since read-integers-from-file is not defined yet. Maybe you meant the function read-setup to be that function? In this case you need to rename your function to read-integers-from-file or the function you are calling to read-setup.

In any case, read-setup will not read the integers from the file. Nothing is returned by your call to loop; in order to make loop to construct and return a list, you should use collect.

For example, all the numbers are printed, but only an empty list is returned (nil = empty list):
cl-user> (loop for i from 1 to 10
              do (print (list i)))

(1) 
(2) 
(3) 
(4) 
(5) 
(6) 
(7) 
(8) 
(9) 
(10) nil
On the other hand, here a list with numbers is created and returned:
cl-user> (loop for i from 1 to 10
              collect i)
(1 2 3 4 5 6 7 8 9 10)
Another thing: you don't need to use coerce. The function read does not return a line from the file, it returns the integers directly.

One thing is not clear: the format of the file. You said that the file contains only numbers, which, to me, means something like this:
23 45 73 18
but your buddy's code suggest that the file contains a list of numbers enclosed by parenthesis, which is this:
(23 45 73 18)
In the first case, you need a loop. In the second case, you just need a single read from the file, because the function read will automatically construct a list when it encounters parenthesis.

By the way, your buddy's code has a bunch of problems, I don't recommend you to use it:
  • He uses variables (meant to be local) without declaring them with let;
  • He uses variables (meant to be global) without declaring them using defvar or defparameter, like you did with *imalist*;
  • He opens a file and doesn't close it afterwards. This is not a problem in you code because you are using with-open-file

Re: Reading In text file.

ya see i tried this
(defun read-setup (thefile)
(with-open-file (stream thefile)
    (loop for line = (read stream nil 'end)
          until (eq line 'end)           
          do (print (list (coerce line 'integer) 
                            )     
              )     
     )
)
)
(defparameter *imalist* (list))

(setf *imalist* (read-setup "thefile.txt"))

then tried (print *imalist*) and it printed nothing :(
but it printed the numbers out correctly however.
SO CLose yet so far away. what exactly am I missing? why isn't it keeping it as a variable *imalist*?
Either way my buddys code is def wrong, ignore that it exists. since the file just has numbers NOT enclosed by parenthesis.

Last edited by Mercenary85 on , edited 1 time in total.

Re: Reading In text file.

Mercenary85 wrote:ya see i tried this
(defun read-setup (thefile)
(with-open-file (stream thefile)
    (loop for line = (read stream nil 'end)
          until (eq line 'end)           
          do (print (list (coerce line 'integer) 
                            )     
              )     
     )
)
)
(defparameter *imalist* (list))

(setf *imalist* (read-setup "thefile.txt"))

then tried (print *imalist*) and it printed nothing :(
but it printed the numbers out correctly however.
SO CLose yet so far away. what exactly am I missing? why isn't it keeping it as a variable *imalist*?
You missed my post.

Re: Reading In text file.

(defun read-setup (file)
  (with-open-file (stream file :direction :input)
    (loop for input = (read stream nil stream)
          until (eq input stream) collect input)))

(defparameter *imalist* (list))

(setf *imalist* (read-setup "thefile.txt"))
would something like this work? it seems to work but I want to make sure im doing it right


edit: CRAP CRAP CRAP. the data i test with is enclosed in paraenthesis (1 5 27 18 19) like that. any way i can modify above code to work? with paranthesis

edit2: Yup it works 100% besides the parenthesis modifier

Last edited by Mercenary85 on , edited 1 time in total.

Re: Reading In text file.

Mercenary85 wrote:
(defun read-setup (file)
  (with-open-file (stream file :direction :input)
    (loop for input = (read stream nil stream)
          until (eq input stream) collect input)))

(defparameter *imalist* (list))

(setf *imalist* (read-setup "thefile.txt"))
would something like this work? it seems to work but I want to make sure im doing it right


edit: CRAP CRAP CRAP. the data i test with is enclosed in paraenthesis (1 5 27 18 19) like that. any way i can modify above code to work? with paranthesis
Your code does work for files without parenthesis.

If it is enclosed by parenthesis, you don't need the loop, just make a single read from the file.

Re: Reading In text file.

gugamilare wrote:
Mercenary85 wrote:
(defun read-setup (file)
  (with-open-file (stream file :direction :input)
    (loop for input = (read stream nil stream)
          until (eq input stream) collect input)))

(defparameter *imalist* (list))

(setf *imalist* (read-setup "thefile.txt"))
would something like this work? it seems to work but I want to make sure im doing it right


edit: CRAP CRAP CRAP. the data i test with is enclosed in paraenthesis (1 5 27 18 19) like that. any way i can modify above code to work? with paranthesis
Your code does work for files without parenthesis.

If it is enclosed by parenthesis, you don't need the loop, just make a single read from the file.
problem is the file looks like this
(36 535 369 837 738 110 817 240 478 483 667 436 186 323 782 256 64 977
815 126 701 888 46 350 830 689 187 833 531 776 979 147 856 949 901 189
92 981 572 307 821 397 911 776 737 899 872 224 674 752 820 541 680 496
532 461 483 642 172 316 312 1 940 957 589 217 671 114 244 109 232 912
575 259 67 86 413 722 540 140 441 791 412 823 492 54 956 572 570 801 15
974 674 529 48 563 748 523 717 10 622 278 229 625 533 880 14 298 992 200
928 210 744 101 172 592 496 472 294 224 678 249 709 438 895 152 129 999
973 354 532 976 669 965 837 585 665 140 574 111 361 701 451 319 114 869
985 49 767 682 215 839 932 645 814 730 187 597 767 856 960 654 642 828
948 667 714 275 623 187 804 535 284 452 261 473 734 982 699 567 431 867
613 858 891 355 153 450 508 881 65 147 161 850 986 401 339 167 53 145)

Re: Reading In text file.

Mercenary85 wrote:problem is the file looks like this
(36 535 369 837 738 110 817 240 478 483 667 436 186 323 782 256 64 977
815 126 701 888 46 350 830 689 187 833 531 776 979 147 856 949 901 189
92 981 572 307 821 397 911 776 737 899 872 224 674 752 820 541 680 496
532 461 483 642 172 316 312 1 940 957 589 217 671 114 244 109 232 912
575 259 67 86 413 722 540 140 441 791 412 823 492 54 956 572 570 801 15
974 674 529 48 563 748 523 717 10 622 278 229 625 533 880 14 298 992 200
928 210 744 101 172 592 496 472 294 224 678 249 709 438 895 152 129 999
973 354 532 976 669 965 837 585 665 140 574 111 361 701 451 319 114 869
985 49 767 682 215 839 932 645 814 730 187 597 767 856 960 654 642 828
948 667 714 275 623 187 804 535 284 452 261 473 734 982 699 567 431 867
613 858 891 355 153 450 508 881 65 147 161 850 986 401 339 167 53 145)
Yes, I got that. Like I said, you need to replace your loop with a single call to read.

Re: Reading In text file.

How do i go about "not" reading the parenthesis parts??

Re: Reading In text file.

Mercenary85 wrote:How do i go about "not" reading the parenthesis parts??
You don't need to "not" read the parenthesis. If some file contains something like this:
(1 2 3 4 5)
then you open that file using with-open-file and you call read directly on the file, the value returned is the list (1 2 3 4 5). You don't even need to create a loop to read the list.

Your Professor put the parenthesis in the file to make it simpler to read it ;)

Re: Reading In text file.

gugamilare wrote:
Mercenary85 wrote:How do i go about "not" reading the parenthesis parts??
You don't need to "not" read the parenthesis. If some file contains something like this:
(1 2 3 4 5)
then you open that file using with-open-file and you call read directly on the file, the value returned is the list (1 2 3 4 5). You don't even need to create a loop to read the list.

Your Professor put the parenthesis in the file to make it simpler to read it ;)
oh haah! fancy that.
welp I got it working. thanks a ton to everyone. especially you gugamilare!

The Assignment was actually a type of averaging/mathmatical stuff on lists, but it was just the readin part i was confused with :) thanks a ton