Skip to content

LISP - Accessing Elements of Vectors

In Common Lisp, a vector is a one-dimensional array. As a fundamental data structure, knowing how to efficiently access its elements is a core skill. This tutorial covers the modern, idiomatic ways to retrieve elements from a vector.

The function aref (short for array reference) is the standard, general-purpose function for accessing elements of any array, including vectors. It is the most common and recommended way to access vector elements in modern Lisp code.

;; Define a vector using the 'vector' constructor for simplicity.
(let ((my-vector (vector 10 20 30 40 50)))
;; Access and print the first element (at index 0).
;; Lisp vectors, like most arrays in programming, are zero-indexed.
(format t "First element: ~a~%" (aref my-vector 0))
;; Access and print the fourth element (at index 3).
(format t "Fourth element: ~a~%" (aref my-vector 3))
)
First element: 10
Fourth element: 40

While aref is universal, Common Lisp provides specialized functions for specific vector types that can offer better performance in compiled code.

A simple vector is a vector that is not displaced, has no fill pointer, and is not adjustable. If you are certain you are working with a simple vector (which is often the case), svref (simple vector reference) can be more efficient than aref because the compiler doesn’t need to check for these special features.

;; The (vector ...) constructor creates a simple vector.
(let ((simple-vec (vector "apple" "banana" "cherry")))
;; Using svref is efficient here.
(format t "Element at index 2: ~s~%" (svref simple-vec 2))
)
Element at index 2: "cherry"

The elt function is a generic accessor for any sequence type, which includes lists, vectors, and strings. You can use elt on a vector, and it will behave just like aref. Its main advantage is in writing functions that can operate on different kinds of sequences without changing the code.

;; A function that gets the second element of any sequence.
(defun get-second-element (sequence)
(when (>= (length sequence) 2)
(elt sequence 1)))
(let ((my-vector #(100 200 300))
(my-list '(a b c)))
(format t "Second element of vector: ~a~%" (get-second-element my-vector))
(format t "Second element of list: ~a~%" (get-second-element my-list)))
Second element of vector: 200
Second element of list: B
  • Default to aref: For general-purpose vector access, aref is the clear choice. It’s readable, universal for all arrays, and modern Lisp compilers are excellent at optimizing it.
  • Use svref for Optimization: Only switch to svref if you are in a performance-critical section of your code and you have profiled it to know that array access is a bottleneck.
  • Use elt for Genericity: Use elt when writing functions that need to be polymorphic over different sequence types.
  • Error: Out-of-Bounds Index: Accessing an index that is negative or greater than or equal to the vector’s length will signal an error. Always ensure your index is within the valid range [0, (length vector) - 1].
  • Debugging Tip: If you get an unexpected out-of-bounds error, use (format t "Accessing vector ~s at index ~d~%" my-vector index) right before the aref call to inspect the values that are causing the problem.