LISP - Creating Vectors
Modern Lisp: Working with Vectors
Section titled “Modern Lisp: Working with Vectors”A vector is a one-dimensional array in Common Lisp. Unlike lists, which are optimized for adding/removing elements at the head, vectors provide fast, constant-time (O(1)) access to any element by its index. This makes them ideal for random-access data storage.
Three Ways to Create a Vector
Section titled “Three Ways to Create a Vector”Common Lisp offers three primary ways to create vectors, each suited for different situations.
1. Using the vector Function
Section titled “1. Using the vector Function”Use the vector function when you know the elements of the vector at the time of creation.
;; Create a vector of numbers(vector 10 20 30) ; => #(10 20 30)
;; Create a vector of mixed types(vector "apple" 3.14 t) ; => #("apple" 3.14 T)2. Using the #(...) Reader Macro
Section titled “2. Using the #(...) Reader Macro”The #(...) syntax is a concise, literal way to define a vector. It’s evaluated by the Lisp reader before the code is even compiled, making it very efficient for constant data.
;; The reader macro is often preferred for constant vectors(defparameter *my-constants* #(1 2 3))(defparameter *fruit* #("apple" "banana" "orange"))3. Using make-array for Maximum Flexibility
Section titled “3. Using make-array for Maximum Flexibility”make-array is the most powerful tool for creating vectors (and multi-dimensional arrays). It allows you to specify the size, an initial value for all elements, the element type, and whether the vector should be adjustable.
;; Create a vector of size 5, with each element initialized to 0(make-array 5 :initial-element 0) ; => #(0 0 0 0 0)
;; Create a vector from a list of initial contents(make-array 3 :initial-contents '(1 2 3)) ; => #(1 2 3)
;; Create a specialized vector that can only hold strings(make-array 4 :element-type 'string :initial-element "empty"); => #("empty" "empty" "empty" "empty")Adjustable Vectors and Fill Pointers
Section titled “Adjustable Vectors and Fill Pointers”For situations where you need a dynamic, growable array (like std::vector in C++ or ArrayList in Java), you can create an adjustable vector with a fill pointer.
The :fill-pointer keeps track of the number of active elements, and :adjustable t allows the vector to be resized if it runs out of space. You add elements using vector-push-extend.
main.lisp
Section titled “main.lisp”;; Create a dynamic vector with an initial capacity of 5(defparameter *dynamic-vector* (make-array 5 :adjustable t :fill-pointer 0))
(print *dynamic-vector*)(format t "Initial length (fill-pointer): ~a~%" (fill-pointer *dynamic-vector*))
;; Add elements to the vector(vector-push-extend 'a *dynamic-vector*)(vector-push-extend 'b *dynamic-vector*)
(print *dynamic-vector*)(format t "New length (fill-pointer): ~a~%" (fill-pointer *dynamic-vector*))
;; Access an element using AREF(format t "First element: ~a~%" (aref *dynamic-vector* 0))Output
Section titled “Output”Executing this code demonstrates the process:
#()Initial length (fill-pointer): 0#(A B)New length (fill-pointer): 2First element: ABest Practices: Lists vs. Vectors
Section titled “Best Practices: Lists vs. Vectors”- Use Lists for: Stacks, sequential processing, and when you frequently add or remove elements from the beginning of the collection. Their strength is
cons,first, andrestoperations. - Use Vectors for: Random access by index, fixed-size collections, or dynamic arrays where you typically add elements to the end. Their strength is the
arefoperation.