LISP - 序列

序列是 LISP 中的一种抽象数据类型。 向量和列表是该数据类型的两个具体子类型。 序列数据类型上定义的所有功能实际上都适用于所有向量和列表类型。

在本节中,我们将讨论序列上最常用的函数。

在开始操作序列(即向量和列表)的各种方法之前,让我们看一下所有可用函数的列表。

创建序列

函数 make-sequence 允许您创建任何类型的序列。 该函数的语法是 −

make-sequence sqtype sqsize &key :initial-element

它创建一个sqtype类型和sqsize长度的序列。

您可以选择使用 :initial-element 参数指定某个值,然后每个元素都将初始化为该值。

例如,创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (make-sequence '(vector float) 
   10 
   :initial-element 1.0))

执行代码时,会返回以下结果 −

#(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0)

序列上的通用函数

序号 函数及说明
1

elt

它允许通过整数索引访问各个元素。

2

length

它返回序列的长度。

3

subseq

它通过提取从特定索引开始并继续到特定结束索引或序列末尾的子序列来返回子序列。

4

copy-seq

它返回一个序列,其中包含与其参数相同的元素。

5

fill

它用于将序列的多个元素设置为单个值。

6

replace

它需要两个序列,并且通过将第二个参数序列中的连续元素复制到第一个参数序列中,对第一个参数序列进行破坏性修改。

7

count

它接受一个项目和一个序列,并返回该项目在序列中出现的次数。

8

reverse

它返回一个序列,其中包含与参数相同的元素,但顺序相反。

9

nreverse

它返回包含与序列相同的元素但顺序相反的相同序列。

10

concatenate

它创建一个包含任意数量序列串联的新序列。

11

position

它接受一个项目和一个序列,并返回该项目在序列中的索引或 nil。

12

find

它需要一个项目和一个序列。 它找到序列中的项目并返回它,如果没有找到则返回 nil。

13

sort

它接受一个序列和一个双参数谓词,并返回序列的排序版本。

14

merge

它需要两个序列和一个谓词,并根据谓词返回通过合并两个序列而产生的序列。

15

map

它接受一个 n 参数函数和 n 个序列,并返回一个新序列,其中包含将该函数应用于序列的后续元素的结果。

16

some

它将谓词作为参数并迭代参数序列,并返回谓词返回的第一个非 NIL 值,或者如果从未满足谓词则返回 false。

17

every

它采用谓词作为参数并迭代参数序列,一旦谓词失败,它就会终止并返回 false。 如果谓词始终满足,则返回 true。

18

notany

它将谓词作为参数并迭代参数序列,一旦满足谓词就返回 false,如果不满足则返回 true。

19

notevery

它将谓词作为参数并迭代参数序列,一旦谓词失败就返回 true,如果谓词始终满足则返回 false。

20

reduce

它映射单个序列,首先将双参数函数应用于序列的前两个元素,然后应用于函数返回的值和序列的后续元素。

21

search

它搜索序列以找到满足某些测试的一个或多个元素。

22

remove

它接受一个项目和一个序列,并返回删除了项目实例的序列。

23

delete

这也接受一个项目和一个序列,并返回一个与参数序列相同类型的序列,该序列具有除该项目之外的相同元素。

24

substitute

它接受一个新项目、一个现有项目和一个序列,并返回一个序列,其中现有项目的实例替换为新项目。

25

nsubstitute

它接受一个新项目、一个现有项目和一个序列,并返回相同的序列,并将现有项目的实例替换为新项目。

26

mismatch

它需要两个序列并返回第一对不匹配元素的索引。

标准序列函数关键字参数

参数 含义 默认值
:test 它是一个双参数函数,用于将项目(或 :key 函数提取的值)与元素进行比较。 EQL
:key 从实际序列元素中提取键值的单参数函数。 NIL 表示按原样使用元素。 NIL
:start 子序列的起始索引(含)。 0
:end 子序列的结束索引(不包括)。 NIL 表示序列结束。
:from-end 如果为 true,则将以相反的顺序从结束到开始遍历序列。
:count 数字表示要删除或替换的元素数量,或 NIL 表示所有元素(仅限 REMOVE 和 SUBSTITUTE)。 NIL

我们刚刚讨论了各种函数和关键字,这些函数和关键字在这些处理序列的函数中用作参数。 在接下来的部分中,我们将通过示例了解如何使用这些函数。

求长度和元素

length 函数返回序列的长度,elt 函数允许您使用整数索引访问各个元素。

示例

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(setq x (vector 'a 'b 'c 'd 'e))
(write (length x))
(terpri)
(write (elt x 3))

执行代码时,会返回以下结果 −

5
D

修改序列

某些序列函数允许迭代序列并执行一些操作,例如搜索、删除、计数或过滤特定元素,而无需编写显式循环。

以下示例演示了这一点 −

Example 1

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (count 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete 5 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (substitute 10 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (find 7 '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (position 5 '(1 5 6 7 8 9 2 7 3 4 5)))

执行代码时,会返回以下结果 −

2
(1 6 7 8 9 2 7 3 4)
(1 6 7 8 9 2 7 3 4)
(1 5 6 10 8 9 2 10 3 4 5)
7
1

Example 2

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (delete-if #'oddp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (delete-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5)))
(terpri)
(write (remove-if #'evenp '(1 5 6 7 8 9 2 7 3 4 5) :count 1 :from-end t))
(terpri)
(setq x (vector 'a 'b 'c 'd 'e 'f 'g))
(fill x 'p :start 1 :end 4)
(write x)

执行代码时,会返回以下结果 −

(6 8 2 4)
(1 5 7 9 7 3 5)
(1 5 6 7 8 9 2 7 3 5)
#(A P P P E F G)

排序和合并序列

排序函数采用一个序列和一个双参数谓词,并返回序列的排序版本。

示例 1

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'<))
(terpri)
(write (sort '(2 4 7 3 9 1 5 4 6 3 8) #'>))
(terpri)

执行代码时,会返回以下结果 −

(1 2 3 3 4 4 5 6 7 8 9)
(9 8 7 6 5 4 4 3 3 2 1)

Example 2

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (merge 'vector #(1 3 5) #(2 4 6) #'<))
(terpri)
(write (merge 'list #(1 3 5) #(2 4 6) #'<))
(terpri)

执行代码时,会返回以下结果 −

#(1 2 3 4 5 6)
(1 2 3 4 5 6)

序列谓词

函数 every、some、notany 和 notever 称为序列谓词。

这些函数迭代序列并测试布尔谓词。

所有这些函数都将谓词作为第一个参数,其余参数是序列。

示例

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (every #'evenp #(2 4 6 8 10)))
(terpri)
(write (some #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (every #'evenp #(2 4 6 8 10 13 14)))
(terpri)
(write (notany #'evenp #(2 4 6 8 10)))
(terpri)
(write (notevery #'evenp #(2 4 6 8 10 13 14)))
(terpri)

执行代码时,会返回以下结果 −

T
T
NIL
NIL
T

映射序列

我们已经讨论了映射函数。 同样,map 函数允许您将函数应用于一个或多个序列的后续元素。

map 函数采用 n 个参数函数和 n 个序列,并在将该函数应用于序列的后续元素后返回一个新序列。

示例

创建一个名为 main.lisp 的新源代码文件,并在其中键入以下代码。

(write (map 'vector #'* #(2 3 4 5) #(3 5 4 8)))

执行代码时,会返回以下结果 −

#(6 15 16 40)