I've been reading various tutorials on alist/plist access but can't figure this out. Let's say i have this file, test.txt:

oranges 1
apples 2
grapes 3

I want to iterate this file line by line, and push it's elements as pairs into a plist or alist. So later when requesting "2" from that plist, I get apples etc. I was thinking something in the line of this:

(defun testRead ()
 (setq myList
       (insert-file-contents "test.txt")
     "\n" t))
  (temp myList)
  (split-string temp " ")
  (plist-put testlist temp)))

Of course above does not work because the dolist part is messed up. First i read the file into myList and split the lines based on newline, then the idea is to iterate this myList and split each element with empty space and push it into a plist. I'm pretty new in lisp and functional programming but I suspect there are more elegant and faster ways to do such thing (parse the file directly into plist) but how?

1 Answer 1


Some things to consider wrt your code (in no special order):

  1. Why use a plist instead of an alist? Either choice is OK, but at least ask yourself the question.

  2. What final plist do you expect to get? Plists generally use symbols, not strings, as the keys. So if you have strings you will want to use intern to get symbols.

  3. If your input is a buffer of such text lines, why convert it to a string and then process that string? In Emacs, it is usually better (easier and faster) to work directly with the buffer.

  4. Why use a global variable for testList? (Maybe there is a good reason?) Why not just bind it within the function and return its value at the end?

  5. plist-put requires two args in addition to the plist to modify: a key and a value. You passed only one arg, which is a string of both key and value. split-string returns a list of the split components - it does not change the value of the variable that points to the original string. If you want to use the list returned then you need to use it explicitly - the variable is not set by split-string to the resulting list.

  6. The key of a plist is typically a symbol. In your case, the key is (intern applied to) the car of what split-string returns for temp, and the value is (string-to-number applied to) the cadr (second element).

  7. Set the plist variable to the result returned by plist-put. You usually need to do this for a destructive operation like plist-put.

This code does what I think you want. It is not the best way to do it. But it corresponds most closely with the approach you were taking, so hopefully it can point out some places where you went a bit wrong.

(defvar testList () "...")

(defun testRead ()
  (let ((myList  (split-string (with-temp-buffer
                                 (insert-file-contents "test.txt")
                                 (buffer-substring-no-properties (point-min) (point-max)))
    (let (f+n)
      (dolist (temp  myList)
        (setq f+n  (split-string temp " "))
        (setq testList  (plist-put testList 
                                   (intern (car f+n))
                                   (string-to-number (cadr f+n))))))))

A good exercise is to do M-x debug-on-entry RET testRead RET, then M-x testRead RET, and then walk through the debugger (using d), to see what happens when Emacs Lisp invokes testRead.

Or insert calls to message at various points, to print out the values of certain expressions (e.g. variables), so you can see if things correspond to what you expected at those points.

In those ways you not only debug your code yourself, you teach yourself Emacs Lisp by seeing just what happens, incrementally.

See the Elisp manual, node Property Lists and its subnodes, including node Plists and Alists.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.