Skip to content

LISP - Getting Subsequence

In Common Lisp, a sequence is a versatile abstract type that includes lists, vectors, and strings. This chapter covers essential functions for accessing elements, creating copies, and extracting subsequences from any of these data types.

The subseq function extracts a portion of a sequence and returns it as a new sequence of the same type.

(subseq sequence start-index &optional end-index)
  • sequence: The source sequence (a list, vector, or string).
  • start-index: The zero-based starting position (inclusive).
  • end-index: An optional zero-based ending position (exclusive). If omitted, it defaults to the end of the sequence.

A new sequence containing the specified elements. The original sequence is not modified.

;; Example with a list
(format t "Sub-list: ~s~%" (subseq '(a b c d e) 1 4))
;; Example with a string
(format t "Substring: ~s~%" (subseq "tutorialspoint" 9))
;; Example with a vector
(format t "Sub-vector: ~s~%" (subseq #(10 20 30 40 50) 0 3))
Sub-list: (B C D)
Substring: "point"
Sub-vector: #(10 20 30)

The copy-seq function creates a shallow copy of a sequence. This is crucial when you need to modify a sequence without affecting the original, preventing unintended side effects.

(copy-seq sequence)
(defparameter *original-list* '(a b c))
(defparameter *copied-list* (copy-seq *original-list*))
;; Modify the copy
(setf (first *copied-list*) 'z)
(format t "Original: ~s~%" *original-list*)
(format t "Copied and modified: ~s~%" *copied-list*)
Original: (A B C)
Copied and modified: (Z B C)

The elt function provides a uniform way to access an element at a specific index in any sequence. The index must be a non-negative integer less than the length of the sequence.

(elt sequence index)

While elt works for all sequences, for performance-critical code, it’s often better to use specialized accessors: aref for vectors/arrays and nth for lists.

;; Accessing an element in a list
(format t "Element from list: ~s~%" (elt '(a b c d e) 2))
;; Accessing a character in a string
(format t "Element from string: ~s~%" (elt "hello" 0))
;; Accessing an element in a vector
(format t "Element from vector: ~s~%" (elt #(10 20 30) 1))
Element from list: C
Element from string: #\h
Element from vector: 20

A common mistake is providing an index that is out of bounds. Doing so will signal a runtime error.

;; This will cause an error!
;; (elt '(a b c) 3)
;; -> The index 3 is out of bounds for the sequence of length 3.

Always ensure your indices are valid, for example, by checking the sequence length with the length function before accessing elements.