Raul Laasner
Raul Laasner

Reputation: 1585

elisp: read file into list of lists

I need to read a file contents into a two-dimensional list, split by newlines and spaces. For example,

a b
c d

needs to become

(list (list "a" "b") (list "c" "d"))

Currently I only know how to read the contents into a simple list determined by newlines. Whenever I need to use an element from that list, I have to split it by spaces everytime, but preferably this should be done only once beforehand.

Upvotes: 2

Views: 1510

Answers (3)

Mirzhan Irkegulov
Mirzhan Irkegulov

Reputation: 18055

With dash, s and f third-party libraries:

(--map (s-split " " it) (s-lines (s-chomp (f-read "FILE.TXT"))))

or:

(->> "FILE.TXT" f-read s-chomp s-lines (--map (s-split " " it)))

which are the same thing.

Upvotes: 2

jch
jch

Reputation: 5651

While abo-abo's answer above is fine, it creates a temporary string with the full contents of the file, which is inefficient. If the file is very large, it is better to walk a buffer collecting data line-by-line:

(defun file-to-matrix (filename)
  (with-temp-buffer
    (insert-file-contents filename)
    (let ((list '()))
      (while (not (eobp))
        (let ((beg (point)))
          (move-end-of-line nil)
          (push (split-string (buffer-substring beg (point)) " ") list)
          (forward-char)))
      (nreverse list))))

Note the use of with-temp-buffer, which avoids leaving a buffer lying around, and the use of insert-file-contents, which avoids interfering with any other buffer that might be visiting the same file.

Upvotes: 4

abo-abo
abo-abo

Reputation: 20342

Like this:

(with-current-buffer (find-file-noselect "~/foo")
  (mapcar (lambda (x) (split-string x " " t))
          (split-string
           (buffer-substring-no-properties (point-min) (point-max))
           "\n"))) 

Upvotes: 2

Related Questions