An improved index function for emacs-lisp

| categories: emacs-lisp | tags:

I previously worked out an index function for a list of strings in emacs-lisp, but at the end I showed it would not work for arbitrary elements of a list. Here is an exercise to improve on that. The goal is a function that looks like this:

(index 1 '("a" 2 1 "b"))

that would return 2 in this case. Last time I used string=, which is why I could not find a number in the list. This time, we will use equal (see http://www.gnu.org/software/emacs/manual/html_node/elisp/Equality-Predicates.html ) which compares components of objects for equality. That should let us find arbitrary objects in a list.

Here is our improved function:

(defun index (object list)
  "return the index of object in list"
  (let ((counter 0)
        (found nil))
    (catch 'finished
      (dolist (listelement list counter)
        (if (equal object listelement)
            (progn
              (setq found t)
              (throw 'finished counter))
          ;; else increment counter
          (incf counter)))
    ;; if we found it return counter otherwise return nil
    (if found counter nil))))

Now, let us test some examples:

(index 1 '("a" 2 1 "b"))
2

No problem finding a number in a list.

(index "b" '("a" 2 1 "b"))
3

How about something more complicated, like a list in a list?

(index '(1 2) '("a" 2 1 (1 2) "b"))
3

That looks good.

(princ (index '(1 2) '("a" 2 1 (2 (1 2)) "b")))
nil

Note, we do not find the nested object. That is ok, the location of that object would require two indices, which this function is not designed for.

Here we consider an object of an a-list

(index '("nut" . "acorn") '(("nut" . "acorn") ("fruit" . "apple")))
0

I am not quite sure how you would use that, but it does illustrate the generality of the index function!

Copyright (C) 2013 by John Kitchin. See the License for information about copying.

org-mode source

Discuss on Twitter