Skip to content

LISP - 获取子序列

在 Common Lisp 中,序列(sequence) 是一种多功能的抽象类型,包括列表、向量和字符串。本章将介绍用于访问元素、创建副本以及从这些数据类型中提取子序列的基本函数。

subseq 函数从序列中提取一部分,并将其作为相同类型的新序列返回。

(subseq sequence start-index &optional end-index)
  • sequence:源序列(列表、向量或字符串)。
  • start-index:起始位置(从零开始,包含)。
  • end-index:可选的结束位置(从零开始,不包含)。如果省略,则默认为序列的末尾。

包含指定元素的新序列。原始序列未被修改。

;; 列表示例
(format t "Sub-list: ~s~%" (subseq '(a b c d e) 1 4))
;; 字符串示例
(format t "Substring: ~s~%" (subseq "tutorialspoint" 9))
;; 向量示例
(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)

copy-seq 函数创建一个序列的浅拷贝。当您需要修改序列而不影响原始序列时,这至关重要,可以防止意外的副作用。

(copy-seq sequence)
(defparameter *original-list* '(a b c))
(defparameter *copied-list* (copy-seq *original-list*))
;; 修改副本
(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)

elt 函数提供了一种统一的方式来访问任何序列中特定索引处的元素。索引必须是一个非负整数,且小于序列的长度。

(elt sequence index)

虽然 elt 适用于所有序列,但对于性能敏感的代码,通常最好使用专门的访问器:aref 用于向量/数组,nth 用于列表。

;; 访问列表中的元素
(format t "Element from list: ~s~%" (elt '(a b c d e) 2))
;; 访问字符串中的字符
(format t "Element from string: ~s~%" (elt "hello" 0))
;; 访问向量中的元素
(format t "Element from vector: ~s~%" (elt #(10 20 30) 1))
Element from list: C
Element from string: #\h
Element from vector: 20

一个常见的错误是提供了超出边界的索引。这样做会导致运行时错误。

;; 这将导致错误!
;; (elt '(a b c) 3)
;; -> 索引 3 超出了长度为 3 的序列的边界。

始终确保您的索引有效,例如,在访问元素之前使用 length 函数检查序列长度。