Emacs Lisp Tutorial: List & Vector

Master emacs+lisp, benefit for life. Testimonials. Thank you for support.
, , …,

This page is a basic tutorial of Emacs Lisp's list & vector datatype. If you don't know emacs lisp, first take a look at Emacs Lisp Basics.

Lisp has vector & list datatypes. These are similar to other language's {list, vector, array}.

Vectors

Elisp has a “vector” datatype. It is similar to C's or Java's array. It has a constant access time but you cannot add/remove element to it. (but you can change a element's value.)

Create Vector

To create a vector, write it like this (vector a b …).

;; creating a vector
(setq v (vector 3 4 5)) ; each element will be evaluated

If you do not want the elements evaluated, write it like this: [a b …].

;; creating a vector
(setq v [3 4 5]) ; each element will NOT be evaluated

Length

(length (vector 3 4 5))

Getting a Element

use elt.

;; get a element from vector
(elt (vector "a" "b" "c") 0) ; ⇒ "a"
;; index starts at 0

Changing a Element

use aset.

(setq v [3 4 5])
(aset v 0 "b")
v  ; ⇒ ["b" 4 5]

Nested Vector

;; nested vector
[[1 2] [3 4]] ; 2 by 2 matrix
;; random nested vector
[8 [3 [2 9] c] 7 [4 "b"]]

Map: mapcar & mapc

One simple way to go thru a vector is using mapcar. Note that it returns a list, not vector.

;; add 1 to each
(mapcar '1+ [3 4 5] ) ; ⇒ (4 5 6)
;; get first element of each row
(mapcar (lambda (x) (elt x 0)) [[1 2] [3 4]] ) ; ⇒ (1 3)

If you want to map to list but don't need the return value, use mapc.

You can also use while. Example:

(setq v [3 4 5])
(setq i 0)

(while (< i (length v))
  (insert (format "%d" (elt v i)))
  (setq i (1+ i))
) ; inserts "345"

Join Vectors

(vconcat sequence1 sequence2 …) → join any sequence types and return a vector. (List and vector are both sequence types.)

(vconcat [3 4] ["a" "b"]) ; ⇒ [3 4 "a" "b"]

Convert Vector to List

(append sequence1 sequence2 …) → join any sequence types and return a list. (List and vector are both sequence types.)

(append [1 2 3] nil) ; ⇒ '(1 2 3)

(info "(elisp) Vector Functions")

List

Create List

To create a list, write it like this (list a b …).

If you do not want the elements evaluated, write it like this: '(a b …).

; assign a list to a var
(setq myList '(a b c))

; prints a list
(message "%S" myList)
;; create a list of values of variables
(let ((x 3) (y 4) (z 5))
  (message "%S" (list x y z))
  ) ; prints "(3 4 5)"

Length

(length ) → return number of elements.

(length (list "a" "b" "c") ) ; ⇒ 3

Get Elements of a List

list element extraction functions
FunctionPurpose
(car )first element
(nth n )nth element (counts from 0)
(car (last ))last element
(car (list "a" "b" "c") )   ; ⇒ "a"
(nth 1 (list "a" "b" "c") ) ; ⇒ "b"
(car (last (list "a" "b" "c")) )   ; ⇒ "c"
sublist functions
FunctionPurpose
(cdr )2nd to last elements, as a list.
(nthcdr n )nth to last elements, as a list.
(butlast n)without the last n elements, as a list.
(cdr (list "a" "b" "c") )   ; ⇒ ("b" "c")

Prepend, Append

Basic List Functions
FunctionPurpose
(cons x )add x to front. (prepend)
(append ℓ1 ℓ2)join two lists
(cons "a" (list "c" "d") ) ; ⇒ ("a" "c" "d")

(cons (list "a" "b") (list "c" "d") ) ; ⇒ (("a" "b") "c" "d")
(append (list "a" "b") (list "c" "d") ) ; ⇒ ("a" "b" "c" "d")
Functions that modify a list variable
FunctionPurpose
(pop )Remove first element from the variable. Returns the removed element.
(nbutlast n)Remove last n elements from the variable. Returns the new value of the variable.
(setcar x)replaces the first element in with x. Returns x.
(setcdr x)replaces the rest of elements in with x. Returns x.
(setq mylist '("a" "b" "c"))
(pop mylist)                            ; ⇒ "a"
(prin1 mylist)                          ; ("b" "c")

The weird names {car, cdr, cons} are like that for historical reasons.

(info "(elisp) Lists")

Map: mapcar & mapc

Here's a typical way of going thru a list. It is done with mapcar.

Following examples use builtin functions:

; add one to each list member using the build in function 1+
(mapcar '1+ (list 1 2 3 4)) ; ⇒ (2 3 4 5)
; take the 1st element of each
(mapcar 'car '((1 2) (3 4) (5 6))) ; ⇒ (1 3 5)

Following examples use user-defined function “lambda” created inline:

; add one to each list member
(mapcar
 (lambda (x) (+ x 1))
 (list 1 2 3 4)
) ; ⇒ (2 3 4 5)
;; take the 2nd element of each
(mapcar (lambda (x) (nth 1 x))
        '((1 2) (3 4) (5 6))) ; ⇒ (2 4 6)

The lambda above means function. It let you define a function in the middle of your code. The form is (lambda (args) body). For example, (lambda (x y) (+ x y)) is a function that takes two arguments, x and y, and returns their sum.

mapc

Use mapc when you don't need the return value.

;; apply a file processing function to a list of files
(mapc 'my-update-html-footer
      (list
       "~/web/3d/viz.html"
       "~/web/3d/viz2.html"
       "~/web/dinju/a.html"
       "~/web/dinju/b.html"
       "~/web/dinju/c.html"
       )
      )

Loop thru List with “while”

Another common form to loop thru a list is using the while function. In each iteration, pop is used to reduce the list. Here's a example of going thru a list using the while function.

(let (myList)
  (setq myList '(a b c))
  (while myList
     (message "%s" (pop myList))
     (sleep-for 1)
  )
)

Number Sequence; Range

(number-sequence n m step) → returns a list of a range of numbers, from n to m, in increment of m.

;; creating a range of numbers
(number-sequence 5)                     ; (5)

(number-sequence 2 9)                   ; (2 3 4 5 6 7 8 9)

(number-sequence 0 9 3)                 ; (0 3 6 9)

List vs Vector

     _____________________________________________
    |                                             |
    |          Sequence                           |
    |  ______   ________________________________  |
    | |      | |                                | |
    | | List | |             Array              | |
    | |      | |    ________       ________     | |
    | |______| |   |        |     |        |    | |
    |          |   | Vector |     | String |    | |
    |          |   |________|     |________|    | |
    |          |  ____________   _____________  | |
    |          | |            | |             | | |
    |          | | Char-table | | Bool-vector | | |
    |          | |____________| |_____________| | |
    |          |________________________________| |
    |_____________________________________________|

Lisp's listvector both are subtypes of the “sequences” datatype. Many functions, such as {elt, mapcar}, work on any sequence type. Here's their primary differences:

Lisp culture is to almost always use list. I recommend using vector as much as possible. Use list ONLY IF you need to constantly grow the list. Even for that case, i recommend using vector by starting with large length, using the function make-vector. 〔☛ Guy Steele on Parallel Programing: Get rid of cons!

You can nest list & vectors in any way. Example:

;; mixed nested list/vector

[ '(3 4) '(5 8) [4 2]]

(list [8 7] '(4 1))

(info "(elisp) Sequences Arrays Vectors")

List of Pairs: Association List & Hash Table

Association List (alist)

Another important datatype similar to list & vector is called Association List (aka alist). It is similar to Python Dictionary, Ruby Hash Table. See: (info "(elisp) Association Lists").

For a example of using alist, see: Emacs Lisp: Batch Script to Validate Matching Brackets.

Hash Table

Elisp also has a true hash table, if you need large number of pairs. See: Emacs Lisp Hash Table.

Like what you read?
Buy Xah Emacs Tutorial
or share some
blog comments powered by Disqus