1 Star 0 Fork 3

rookieagle/Elisp

forked from advanceflow/Elisp 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
06-序列、数组和向量.org 46.64 KB
一键复制 编辑 原始数据 按行查看 历史
advanceflow 提交于 2022-05-28 10:12 . finish s2

6 序列、数组和向量

序列类型是另外两种 Lisp 类型的联合:列表和数组。 换句话说,任何列表都是序列,任何数组都是序列。 所有序列的共同属性是每个序列都是有序的元素集合。

数组是一个固定长度的对象,每个元素都有一个槽。 所有元素都可以在恒定时间内访问。 数组的四种类型是字符串、向量、字符表和布尔向量。

列表是一系列元素,但它不是单个原始对象; 它由 cons 单元格组成,每个元素一个单元格。 查找第 n 个元素需要查看 n 个 cons 单元格,因此距离列表开头较远的元素需要更长的时间才能访问。 但是可以将元素添加到列表中,或者删除元素。

下图显示了这些类型之间的关系:

 _____________________________________________
|                                             |
|          Sequence                           |
|  ______   ________________________________  |
| |      | |                                | |
| | List | |             Array              | |
| |      | |    ________       ________     | |
| |______| |   |        |     |        |    | |
|          |   | Vector |     | String |    | |
|          |   |________|     |________|    | |
|          |  ____________   _____________  | |
|          | |            | |             | | |
|          | | Char-table | | Bool-vector | | |
|          | |____________| |_____________| | |
|          |________________________________| |
|_____________________________________________|

6.1 序列

本节介绍接受任何类型序列的函数。

Function: sequencep object ¶

如果对象是列表、向量、字符串、布尔向量或字符表,则此函数返回 t,否则返回 nil。 另请参见下面的 seqp。

Function: length sequence ¶

此函数返回序列中元素的数量。 如果参数不是序列或点列表,则函数会发出错误类型参数错误的信号; 如果参数是循环列表,它会发出循环列表错误信号。 对于 char-table,返回的值总是比最大​​ Emacs 字符代码大一。

有关安全长度的相关功能,请参见安全长度的定义。



   (length '(1 2 3))
	  ⇒ 3

   (length ())
	  ⇒ 0

   (length "foobar")
	  ⇒ 6

   (length [1 2 3])
	  ⇒ 3

   (length (make-bool-vector 5 nil))
	  ⇒ 5

另请参阅文本表示中的字符串字节。

如果您需要计算显示字符串的宽度,您应该使用字符串宽度(请参阅显示文本的大小),而不是长度,因为长度仅计算字符数,但不考虑每个字符的显示宽度.

Function: length< sequence length ¶

如果序列短于长度,则返回非零。 如果序列是一个长列表,这可能比计算序列的长度更有效。

Function: length> sequence length ¶

如果序列长于长度,则返回非零。

Function: length= sequence length ¶

如果序列的长度等于长度,则返回非零。

Function: elt sequence index ¶

此函数返回由索引索引的序列元素。 index 的合法值是从 0 到比序列长度小 1 的整数。 如果序列是一个列表,超出范围的值的行为与第 n 个相同。 请参见第 n 个的定义。 否则,超出范围的值会触发 args-out-of-range 错误。

  (elt [1 2 3 4] 2)
	   ⇒ 3

  (elt '(1 2 3 4) 2)
	   ⇒ 3

  ;; We use string to show clearly which character elt returns.
  (string (elt "1234" 2))
	   ⇒ "3"

  (elt [1 2 3 4] 4)
	   error→ Args out of range: [1 2 3 4], 4

  (elt [1 2 3 4] -1)
	   error→ Args out of range: [1 2 3 4], -1

此函数概括了 aref(请参阅对数组进行操作的函数)和 nth(请参阅 nth 的定义)。

Function: copy-sequence seqr ¶

此函数返回 seqr 的副本,它应该是序列或记录。 副本是与原始对象相同类型的对象,并且具有相同顺序的相同元素。 但是,如果 seqr 为空,如字符串或长度为零的向量,则此函数返回的值可能不是副本,而是与 seqr 相同类型且相同的空对象。

将新元素存储到副本中不会影响原始 seqr,反之亦然。 但是,副本的元素不是副本; 它们与原始元素相同(eq)。 因此,在这些元素中所做的更改(通过副本找到)在原始文件中也可见。

如果参数是具有文本属性的字符串,则副本中的属性列表本身就是副本,不与原始属性列表共享。 但是,属性的​​实际值是共享的。 请参阅文本属性。

此功能不适用于点列表。 尝试复制循环列表可能会导致无限循环。

另请参阅 Building Cons Cells and Lists 中的 append、Creating Strings 中的 concat 和 Vectors 函数中的 vconcat,了解其他复制序列的方法。

  (setq bar (list 1 2))
	   ⇒ (1 2)

  (setq x (vector 'foo bar))
	   ⇒ [foo (1 2)]

  (setq y (copy-sequence x))
	   ⇒ [foo (1 2)]


  (eq x y)
	   ⇒ nil

  (equal x y)
	   ⇒ t

  (eq (elt x 1) (elt y 1))
	   ⇒ t


  ;; Replacing an element of one sequence.
  (aset x 0 'quux)
  x ⇒ [quux (1 2)]
  y ⇒ [foo (1 2)]


  ;; Modifying the inside of a shared element.
  (setcar (aref x 1) 69)
  x ⇒ [quux (69 2)]
  y ⇒ [foo (69 2)]
Function: reverse sequence ¶

此函数创建一个新序列,其元素是序列的元素,但顺序相反。 原始参数序列不会改变。 请注意,字符表不能颠倒。

  (setq x '(1 2 3 4))
	   ⇒ (1 2 3 4)

  (reverse x)
	   ⇒ (4 3 2 1)
  x
	   ⇒ (1 2 3 4)

  (setq x [1 2 3 4])
	   ⇒ [1 2 3 4]

  (reverse x)
	   ⇒ [4 3 2 1]
  x
	   ⇒ [1 2 3 4]

  (setq x "xyzzy")
	   ⇒ "xyzzy"

  (reverse x)
	   ⇒ "yzzyx"
  x
	   ⇒ "xyzzy"

Function: nreverse sequence ¶

此函数反转序列元素的顺序。 与反向不同,原始序列可能会被修改。

例如:

  (setq x (list 'a 'b 'c))
	   ⇒ (a b c)

  x
	   ⇒ (a b c)
  (nreverse x)
	   ⇒ (c b a)

  ;; The cons cell that was first is now last.
  x
	   ⇒ (a)

为避免混淆,我们通常将 nreverse 的结果存储回保存原始列表的同一变量中:

(setq x (nreverse x))

这是我们最喜欢的示例 (abc) 的逆向,以图形方式呈现:

   Original list head:                       Reversed list:
    -------------        -------------        ------------
   | car  | cdr  |      | car  | cdr  |      | car | cdr  |
   |   a  |  nil |<--   |   b  |   o  |<--   |   c |   o  |
   |      |      |   |  |      |   |  |   |  |     |   |  |
    -------------    |   --------- | -    |   -------- | -
			|             |      |            |
			 -------------        ------------

对于向量,它甚至更简单,因为您不需要 setq:

  (setq x (copy-sequence [1 2 3 4]))
	   ⇒ [1 2 3 4]
  (nreverse x)
	   ⇒ [4 3 2 1]
  x
	   ⇒ [4 3 2 1]

请注意,与 reverse 不同,此函数不适用于字符串。 尽管您可以使用 aset 更改字符串数据,但强烈建议将字符串视为不可变的,即使它们是可变的。 请参阅可变性。

Function: sort sequence predicate ¶

此功能对序列进行稳定排序。 请注意,此功能不适用于所有序列; 它只能用于列表和向量。 如果序列是一个列表,它会被破坏性地修改。 此函数返回排序后的序列并使用谓词比较元素。 稳定排序是排序键相同的元素在排序前后保持其相对顺序的排序。 当连续排序用于根据不同标准对元素进行排序时,稳定性很重要。

参数谓词必须是接受两个参数的函数。 它用两个序列元素调用。 要获得升序排序,如果第一个元素“小于”第二个元素,则谓词应返回非零,否则返回 nil。

比较函数谓词必须为任何给定的参数对提供可靠的结果,至少在一次排序调用中。 它必须是反对称的; 也就是说,如果 a 小于 b,则 b 不能小于 a。 它必须是可传递的——也就是说,如果 a 小于 b,并且 b 小于 c,那么 a 必须小于 c。 如果使用不满足这些要求的比较函数,排序的结果是不可预测的。

列表排序的破坏性方面是它通过更改 CDR 重新排列 cons 单元形成序列。 非破坏性排序函数将创建新的 cons 单元格以按排序顺序存储元素。 如果您希望在不破坏原件的情况下制作排序副本,请先使用复制顺序复制它,然后再排序。

排序不会按顺序改变 cons 单元格的 CAR; 原本在序列中包含元素a的cons单元格在排序后在其CAR中仍有a,但由于CDR的变化,它现在出现在列表中的不同位置。 例如:

  (setq nums (list 1 3 2 6 5 4 0))
	   ⇒ (1 3 2 6 5 4 0)

  (sort nums #'<)
	   ⇒ (0 1 2 3 4 5 6)

  nums
	   ⇒ (1 2 3 4 5 6)

警告:注意 nums 中的列表不再包含 0; 这是与以前相同的缺点单元格,但它不再是列表中的第一个。 不要假设以前持有参数的变量现在持有整个排序列表! 相反,保存排序结果并使用它。 大多数情况下,我们将结果存储回保存原始列表的变量中:

(setq nums (sort nums #'<))

为了更好地理解什么是稳定排序,请考虑以下向量示例。 排序后,car 为 8 的所有 item 都分组在 vector 的开头,但它们的相对顺序保持不变。 car 为 9 的所有项目都分组在向量的末尾,但它们的相对顺序也被保留:

     (setq
	vector
	(vector '(8 . "xxx") '(9 . "aaa") '(8 . "bbb") '(9 . "zzz")
		'(9 . "ppp") '(8 . "ttt") '(8 . "eee") '(9 . "fff")))
	   ⇒ [(8 . "xxx") (9 . "aaa") (8 . "bbb") (9 . "zzz")
	       (9 . "ppp") (8 . "ttt") (8 . "eee") (9 . "fff")]

     (sort vector (lambda (x y) (< (car x) (car y))))
	   ⇒ [(8 . "xxx") (8 . "bbb") (8 . "ttt") (8 . "eee")
	       (9 . "aaa") (9 . "zzz") (9 . "ppp") (9 . "fff")]

有关执行排序的更多功能,请参阅排序文本。 有关排序的有用示例,请参阅访问文档字符串中的文档。

seq.el 库提供以下附加的序列操作宏和函数,前缀为 seq-。 要使用它们,您必须首先加载 seq 库。

这个库中定义的所有函数都没有副作用; 即,它们不会修改您作为参数传递的任何序列(列表、向量或字符串)。 除非另有说明,否则结果是与输入相同类型的序列。 对于那些接受谓词的函数,这应该是一个参数的函数。

seq.el 库可以扩展为使用其他类型的顺序数据结构。 为此,所有函数都使用 cl-defgeneric 定义。 有关使用 cl-defgeneric 添加扩展的更多详细信息,请参阅通用函数。

Function: seq-elt sequence index ¶

此函数返回指定索引处的序列元素,该元素是一个整数,其有效值范围是零到比序列长度小一。 对于内置序列类型的超出范围的值,seq-elt 的行为类似于 elt。 详见 elt 的定义。

(seq-elt [1 2 3 4] 2)
⇒ 3

seq-elt 返回可使用 setf 设置的位置(请参阅 setf 宏)。

(setq vec [1 2 3 4])
(setf (seq-elt vec 2) 5)
vec
⇒ [1 2 5 4]
Function: seq-length sequence ¶

此函数返回序列中元素的数量。 对于内置序列类型,seq-length 的行为类似于长度。 见长度定义。

Function: seqp object ¶

如果 object 是一个序列(列表或数组)或通过 seq.el 泛型函数定义的任何其他类型的序列,则此函数返回非 nil。 这是 sequencep 的可扩展变体。

(seqp [1 2])
⇒ t

(seqp 2)
⇒ nil
Function: seq-drop sequence n ¶

此函数返回除序列的前 n(整数)个元素之外的所有元素。 如果 n 为负数或零,则结果为序列。

(seq-drop [1 2 3 4 5 6] 3)
⇒ [4 5 6]

(seq-drop "hello world" -4)
⇒ "hello world"

Function: seq-take sequence n ¶

此函数返回序列的前 n 个(整数)元素。 如果 n 为负数或零,则结果为零。

(seq-take '(1 2 3 4) 3)
⇒ (1 2 3)

(seq-take [1 2 3 4] 0)
⇒ []
Function: seq-take-while predicate sequence ¶

此函数按顺序返回序列的成员,在谓词返回 nil 的第一个成员之前停止。

(seq-take-while (lambda (elt) (> elt 0)) '(1 2 3 -1 -2))
⇒ (1 2 3)

(seq-take-while (lambda (elt) (> elt 0)) [-1 4 6])
⇒ []
Function: seq-drop-while predicate sequence ¶

此函数按顺序返回序列的成员,从谓词返回 nil 的第一个成员开始。

(seq-drop-while (lambda (elt) (> elt 0)) '(1 2 3 -1 -2))
⇒ (-1 -2)

(seq-drop-while (lambda (elt) (< elt 0)) [1 4 6])
⇒ [1 4 6]
Function: seq-do function sequence ¶

此函数依次将函数应用于序列的每个元素(可能是为了副作用),并返回序列。

Function: seq-map function sequence ¶

此函数返回将函数应用于序列的每个元素的结果。 返回值是一个列表。

(seq-map #'1+ '(2 4 6))
⇒ (3 5 7)

(seq-map #'symbol-name [foo bar])
⇒ ("foo" "bar")
Function: seq-map-indexed function sequence ¶

此函数返回将函数应用于序列的每个元素及其在 seq 中的索引的结果。 返回值是一个列表。

  (seq-map-indexed (lambda (elt idx)
			 (list idx elt))
		       '(a b c))
  ⇒ ((0 a) (1 b) (2 c))
Function: seq-mapn function &rest sequences ¶

此函数返回将函数应用于序列的每个元素的结果。 function 的 arity (参见 subr-arity )必须与序列的数量相匹配。 映射在最短序列的末尾停止,返回值是一个列表。



(seq-mapn #'+ '(2 4 6) '(20 40 60))
⇒ (22 44 66)

(seq-mapn #'concat '("moskito" "bite") ["bee" "sting"])
⇒ ("moskitobee" "bitesting")
Function: seq-filter predicate sequence ¶

此函数返回谓词返回非零的序列中所有元素的列表。

(seq-filter (lambda (elt) (> elt 0)) [1 -1 3 -3 5])
⇒ (1 3 5)

(seq-filter (lambda (elt) (> elt 0)) '(-1 -3 -5))
⇒ nil
Function: seq-remove predicate sequence ¶

此函数返回谓词返回 nil 的序列中所有元素的列表。

(seq-remove (lambda (elt) (> elt 0)) [1 -1 3 -3 5])
⇒ (-1 -3)

(seq-remove (lambda (elt) (< elt 0)) '(-1 -3 -5))
⇒ nil
Function: seq-reduce function sequence initial-value ¶

这个函数返回用初始值和序列的第一个元素调用函数的结果,然后用那个结果和序列的第二个元素调用函数,然后用那个结果和序列的第三个元素调用函数,等等。函数应该是一个函数的两个论点。

使用两个参数调用函数。 初始值(然后是累加值)用作第一个参数,序列中的元素用作第二个参数。

如果序列为空,则返回初始值而不调用函数。

(seq-reduce #'+ [1 2 3 4] 0)
⇒ 10

(seq-reduce #'+ '(1 2 3 4) 5)
⇒ 15

(seq-reduce #'+ '() 3)
⇒ 3
Function: seq-some predicate sequence ¶

此函数返回通过依次将谓词应用于序列的每个元素而返回的第一个非零值。

(seq-some #'numberp ["abc" 1 nil])
⇒ t

(seq-some #'numberp ["abc" "def"])
⇒ nil

(seq-some #'null ["abc" 1 nil])
⇒ t

(seq-some #'1+ [2 4 6])
⇒ 3
Function: seq-find predicate sequence &optional default ¶

此函数返回谓词返回非零的序列中的第一个元素。 如果没有元素与谓词匹配,则函数返回默认值。

请注意,如果找到的元素与默认元素相同,则此函数具有歧义,因为在这种情况下,无法知道是否找到了元素。



(seq-find #'numberp ["abc" 1 nil])
⇒ 1

(seq-find #'numberp ["abc" "def"])
⇒ nil

Function: seq-every-p predicate sequence ¶

如果将谓词应用于序列的每个元素返回非零,则此函数返回非零。



(seq-every-p #'numberp [2 4 6])
⇒ t

(seq-every-p #'numberp [2 4 "6"])
⇒ nil
Function: seq-empty-p sequence ¶

如果序列为空,此函数返回非零。

(seq-empty-p "not empty")
⇒ nil

(seq-empty-p "")
⇒ t
Function: seq-count predicate sequence ¶

此函数返回谓词返回非零的序列中元素的数量。

(seq-count (lambda (elt) (> elt 0)) [-1 2 0 3 -2])
⇒ 2
Function: seq-sort function sequence ¶

此函数返回根据函数排序的序列副本,如果第一个参数应在第二个参数之前排序,则返回非 nil 的两个参数的函数。

Function: seq-sort-by function predicate sequence ¶

此功能类似于 seq-sort,但序列的元素在排序之前通过对其应用函数进行转换。 function 是一个参数的函数。

(seq-sort-by #'seq-length #'> ["a" "ab" "abc"])
⇒ ["abc" "ab" "a"]
Function: seq-contains-p sequence elt &optional function ¶

如果序列中至少有一个元素等于 elt,则此函数返回非 nil。 如果可选参数函数不为 nil,则它是一个使用两个参数的函数,而不是默认的 equal。

(seq-contains-p '(symbol1 symbol2) 'symbol1)
⇒ t

(seq-contains-p '(symbol1 symbol2) 'symbol3)
⇒ nil
Function: seq-set-equal-p sequence1 sequence2 &optional testfn ¶

此函数检查 sequence1 和 sequence2 是否包含相同的元素,而不管顺序如何。 如果可选参数 testfn 不是 nil,它是一个使用两个参数的函数,而不是默认的 equal。



(seq-set-equal-p '(a b c) '(c b a))
⇒ t

(seq-set-equal-p '(a b c) '(c b))
⇒ nil

(seq-set-equal-p '("a" "b" "c") '("c" "b" "a"))
⇒ t

(seq-set-equal-p '("a" "b" "c") '("c" "b" "a") #'eq)
⇒ nil
Function: seq-position sequence elt &optional function ¶

此函数返回序列中等于 elt 的第一个元素的索引。 如果可选参数函数不为 nil,则它是一个使用两个参数的函数,而不是默认的 equal。

(seq-position '(a b c) 'b)
⇒ 1

(seq-position '(a b c) 'd)
⇒ nil
Function: seq-uniq sequence &optional function ¶

此函数返回删除重复项的序列元素列表。 如果可选参数函数不为 nil,则它是一个使用两个参数的函数,而不是默认的 equal。

(seq-uniq '(1 2 2 1 3))
⇒ (1 2 3)

(seq-uniq '(1 2 2.0 1.0) #'=)
⇒ (1 2)
Function: seq-subseq sequence start &optional end ¶

此函数返回从开始到结束的序列子集,均为整数(结束默认为最后一个元素)。 如果 start 或 end 为负数,则从序列的末尾开始计数。

(seq-subseq '(1 2 3 4 5) 1)
⇒ (2 3 4 5)

(seq-subseq '[1 2 3 4 5] 1 3)
⇒ [2 3]

(seq-subseq '[1 2 3 4 5] -3 -1)
⇒ [3 4]
Function: seq-concatenate type &rest sequences ¶

此函数返回由序列串联组成的类型类型序列。 类型可以是:向量、列表或字符串。

(seq-concatenate 'list '(1 2) '(3 4) [5 6])
⇒ (1 2 3 4 5 6)

(seq-concatenate 'string "Hello " "world")
⇒ "Hello world"
Function: seq-mapcat function sequence &optional type ¶

此函数将应用 seq-concatenate 的结果返回到将函数应用于序列的每个元素的结果。 结果是类型类型的序列,如果类型为 nil,则为列表。

(seq-mapcat #'seq-reverse '((3 2 1) (6 5 4)))
⇒ (1 2 3 4 5 6)

Function: seq-partition sequence n ¶

此函数返回序列元素的列表,这些元素被分组为长度为 n 的子序列。 最后一个序列可能包含比 n 少的元素。 n 必须是整数。 如果 n 为负整数或 0,则返回值为 nil。

(seq-partition '(0 1 2 3 4 5 6 7) 3)
⇒ ((0 1 2) (3 4 5) (6 7))
Function: seq-union sequence1 sequence2 &optional function ¶

此函数返回出现在 sequence1 或 sequence2 中的元素列表。 返回列表的元素都是唯一的,因为没有两个元素会比较相等。 如果可选参数函数不为 nil,则它应该是用于比较元素的两个参数的函数,而不是默认的 equal。

(seq-union [1 2 3] [3 5])
⇒ (1 2 3 5)
Function: seq-intersection sequence1 sequence2 &optional function ¶

此函数返回同时出现在 sequence1 和 sequence2 中的元素列表。 如果可选参数函数不为 nil,则它是用于比较元素的两个参数的函数,而不是默认的 equal。

(seq-intersection [2 3 4 5] [1 3 5 6 7])
⇒ (3 5)
Function: seq-difference sequence1 sequence2 &optional function ¶

此函数返回出现在序列 1 中但未出现在序列 2 中的元素列表。 如果可选参数函数不为 nil,则它是用于比较元素的两个参数的函数,而不是默认的 equal。

(seq-difference '(2 3 4 5) [1 3 5 6 7])
⇒ (2 4)
Function: seq-group-by function sequence ¶

该函数将序列的元素分成一个列表,其键是对序列的每个元素应用函数的结果。 使用 equal 比较键。

(seq-group-by #'integerp '(1 2.1 3 2 3.2))
⇒ ((t 1 3 2) (nil 2.1 3.2))

(seq-group-by #'car '((a 1) (b 2) (a 3) (c 4)))
⇒ ((b (b 2)) (a (a 1) (a 3)) (c (c 4)))
Function: seq-into sequence type ¶

该函数将序列序列转换为类型类型的序列。 type 可以是以下符号之一:向量、字符串或列表。

(seq-into [1 2 3] 'list)
⇒ (1 2 3)

(seq-into nil 'vector)
⇒ []

(seq-into "hello" 'vector)
⇒ [104 101 108 108 111]
Function: seq-min sequence ¶

此函数返回序列的最小元素。 序列的元素必须是数字或标记(请参阅标记)。

(seq-min [3 1 2])
⇒ 1

(seq-min "Hello")
⇒ 72
Function: seq-max sequence ¶

此函数返回序列的最大元素。 序列的元素必须是数字或标记。

(seq-max [1 3 2])
⇒ 3

(seq-max "Hello")
⇒ 111
Macro: seq-doseq (var sequence) body… ¶

这个宏类似于 dolist(参见 dolist),只是序列可以是列表、向量或字符串。 这主要用于副作用。

Macro: seq-let var-sequence val-sequence body… ¶

此宏将 var-sequence 中定义的变量绑定到作为 val-sequence 的相应元素的值。 这称为解构绑定。 var-sequence 的元素本身可以包含序列,允许嵌套解构。

var-sequence 序列还可以包括 &rest 标记,后跟要绑定到 val-sequence 其余部分的变量名。

     (seq-let [first second] [1 2 3 4]
	(list first second))
     ⇒ (1 2)

     (seq-let (_ a _ b) '(1 2 3 4)
	(list a b))
     ⇒ (2 4)

     (seq-let [a [b [c]]] [1 [2 [3]]]
	(list a b c))
     ⇒ (1 2 3)

     (seq-let [a b &rest others] [1 2 3 4]
	others)

     ⇒ [3 4]

pcase 模式为解构绑定提供了另一种工具,请参阅使用 pcase 模式进行解构。

Macro: seq-setq var-sequence val-sequence ¶

这个宏的工作方式与 seq-let 类似,不同之处在于将值分配给变量,就像通过 setq 而不是在 let 绑定中一样。

     (let ((a nil)
	    (b nil))
	(seq-setq (_ a _ b) '(1 2 3 4))
	(list a b))
     ⇒ (2 4)
Function: seq-random-elt sequence ¶

此函数返回随机获取的序列元素。

(seq-random-elt [1 2 3 4])
⇒ 3
(seq-random-elt [1 2 3 4])
⇒ 2
(seq-random-elt [1 2 3 4])
⇒ 4
(seq-random-elt [1 2 3 4])
⇒ 2
(seq-random-elt [1 2 3 4])
⇒ 1

如果序列为空,则此函数发出错误信号。

6.2 数组

一个数组对象有多个槽,其中包含许多其他的 Lisp 对象,称为数组的元素。 可以在恒定时间内访问数组的任何元素。 相反,访问列表元素的时间与该元素在列表中的位置成正比。

Emacs 定义了四种类型的数组,都是一维的:字符串(参见字符串类型)、向量(参见向量类型)、布尔向量(参见布尔向量类型)和字符表(参见字符表类型)。 向量和字符表可以保存任何类型的元素,但字符串只能保存字符,而布尔向量只能保存 t 和 nil。

所有四种阵列都具有以下特征:

数组的第一个元素的索引为零,第二个元素的索引为 1,依此类推。 这称为零原点索引。 例如,一个包含四个元素的数组的索引为 0、1、2 和 3。 数组的长度在创建后是固定的; 您不能更改现有数组的长度。 出于求值的目的,数组是一个常数——即,它对自身求值。 数组的元素可以分别用函数 aref 和 aset 引用或更改(请参阅对数组进行操作的函数)。

当你创建一个数组时,除了一个字符表,你必须指定它的长度。 您不能指定字符表的长度,因为这是由字符代码的范围决定的。

原则上,如果你想要一个文本字符数组,你可以使用字符串或向量。 在实践中,我们总是为此类应用选择字符串,原因有四个:

它们占据相同元素向量空间的四分之一。 字符串以文本形式更清晰地显示内容的方式打印。 字符串可以保存文本属性。 请参阅文本属性。 Emacs 的许多专门的编辑和 I/O 工具只接受字符串。 例如,您不能像插入字符串那样将字符向量插入缓冲区。 请参阅字符串和字符。

相比之下,对于键盘输入字符数组(例如键序列),可能需要一个向量,因为许多键盘输入字符超出了适合字符串的范围。 请参阅按键序列输入。

6.3 操作数组的函数

在本节中,我们将描述接受所有类型数组的函数。

Function: arrayp object ¶

如果对象是数组(即向量、字符串、布尔向量或字符表),则此函数返回 t。

  (arrayp [a])
	   ⇒ t
  (arrayp "asdf")
	   ⇒ t
  (arrayp (syntax-table))    ;; A char-table.
	   ⇒ t
Function: aref arr index ¶

此函数返回数组或记录 arr 的索引元素。 第一个元素的索引为零。

  (setq primes [2 3 5 7 11 13])
	   ⇒ [2 3 5 7 11 13]
  (aref primes 4)
	   ⇒ 11

  (aref "abcdefg" 1)
	   ⇒ 98           ; ‘b’ is ASCII code 98.

另请参见序列中的函数 elt。

Function: aset array index object ¶

此函数将数组的第一个元素设置为对象。 它返回对象。

  (setq w (vector 'foo 'bar 'baz))
	   ⇒ [foo bar baz]
  (aset w 0 'fu)
	   ⇒ fu
  w
	   ⇒ [fu bar baz]


  ;; copy-sequence copies the string to be modified later.
  (setq x (copy-sequence "asdfasfd"))
	   ⇒ "asdfasfd"
  (aset x 3 ?Z)
	   ⇒ 90
  x
	   ⇒ "asdZasfd"

数组应该是可变的。 请参阅可变性。

如果数组是字符串而对象不是字符,则会导致错误类型参数错误。 如果需要插入字符,该函数会将单字节字符串转换为多字节。

Function: fillarray array object ¶

该函数用对象填充数组数组,使数组的每个元素都是对象。 它返回数组。

  (setq a (copy-sequence [a b c d e f g]))
	   ⇒ [a b c d e f g]
  (fillarray a 0)
	   ⇒ [0 0 0 0 0 0 0]
  a
	   ⇒ [0 0 0 0 0 0 0]

  (setq s (copy-sequence "When in the course"))
	   ⇒ "When in the course"
  (fillarray s ?-)
	   ⇒ "------------------"

如果数组是字符串而对象不是字符,则会导致错误类型参数错误。

通用序列函数 copy-sequence 和 length 通常对已知为数组的对象很有用。 请参阅序列。

6.4 向量

向量是一个通用数组,其元素可以是任何 Lisp 对象。 (相比之下,字符串的元素只能是字符。请参阅字符串和字符。)向量在 Emacs 中用于多种用途:作为键序列(请参阅键序列),作为符号查找表(请参阅创建和内部符号) ,作为字节编译函数表示的一部分(请参阅字节编译)等。

与其他数组一样,向量使用零原点索引:第一个元素的索引为 0。

向量在元素周围用方括号打印。 因此,元素为符号 a、b 和 a 的向量被打印为 [aba]。 您可以在 Lisp 输入中以相同的方式编写向量。

向量,如字符串或数字,被认为是评估的常数:评估它的结果是相同的向量。 这不会评估甚至检查向量的元素。 请参阅自我评估表。 用方括号编写的向量不应通过 aset 或其他破坏性操作进行修改。 请参阅可变性。

以下是说明这些原则的示例:

(setq avector [1 two '(three) "four" [five]])
     ⇒ [1 two '(three) "four" [five]]
(eval avector)
     ⇒ [1 two '(three) "four" [five]]
(eq avector (eval avector))
     ⇒ t

6.5 向量函数

以下是一些与向量相关的函数:

Function: vectorp object ¶

如果 object 是向量,则此函数返回 t。

  (vectorp [a])
	   ⇒ t
  (vectorp "asdf")
	   ⇒ nil
Function: vector &rest objects ¶

此函数创建并返回一个向量,其元素是参数、对象。

  (vector 'foo 23 [bar baz] "rats")
	   ⇒ [foo 23 [bar baz] "rats"]
  (vector)
	   ⇒ []
Function: make-vector length object ¶

此函数返回一个由长度元素组成的新向量,每个元素都初始化为对象。

  (setq sleepy (make-vector 9 'Z))
	   ⇒ [Z Z Z Z Z Z Z Z Z]
Function: vconcat &rest sequences ¶

此函数返回一个包含序列所有元素的新向量。 参数序列可以是正确的列表、向量、字符串或布尔向量。 如果没有给出序列,则返回空向量。

该值要么是空向量,要么是新构造的非空向量,它与任何现有向量都不相等。

  (setq a (vconcat '(A B C) '(D E F)))
	   ⇒ [A B C D E F]
  (eq a (vconcat a))
	   ⇒ nil

  (vconcat)
	   ⇒ []
  (vconcat [A B C] "aa" '(foo (6 7)))
	   ⇒ [A B C 97 97 foo (6 7)]

vconcat 函数还允许字节码函数对象作为参数。 这是一个特殊功能,可以轻松访问字节码函数对象的全部内容。 请参阅字节码函数对象。

有关其他连接函数,请参阅映射函数中的 mapconcat、创建字符串中的 concat 和构建 Cons 单元格和列表中的 append。

append 函数还提供了一种将向量转换为具有相同元素的列表的方法:

(setq avector [1 two (quote (three)) "four" [five]])
     ⇒ [1 two '(three) "four" [five]]
(append avector nil)
     ⇒ (1 two '(three) "four" [five])

6.6 字符表

一个字符表很像一个向量,除了它是由字符代码索引的。 任何没有修饰符的有效字符代码都可以用作字符表中的索引。 与任何数组一样,您可以使用 aref 和 aset 访问 char-table 的元素。 此外,一个字符表可以有额外的槽来保存与特定字符代码无关的附加数据。 与向量一样,char-tables 在求值时是常量,可以保存任何类型的元素。

每个字符表都有一个子类型,一个符号,它有两个用途:

子类型提供了一种简单的方法来判断 char-table 的用途。 例如,显示表是以display-table为子类型的char-table,语法表是以syntax-table为子类型的char-table。 可以使用函数 char-table-subtype 查询子类型,如下所述。 子类型控制字符表中额外槽的数量。 此数字由子类型的 char-table-extra-slots 符号属性指定(请参阅符号属性),其值应为 0 到 10 之间的整数。如果子类型没有此类符号属性,则 char-table 没有额外的槽.

一个 char-table 可以有一个 parent,它是另一个 char-table。 如果是这样,那么每当 char-table 为特定字符 c 指定 nil 时,它都会继承父级中指定的值。 换句话说,如果 char-table 本身指定 nil,则 (aref char-table c) 从 char-table 的父级返回值。

一个字符表也可以有一个默认值。 如果是这样,那么 (aref char-table c) 会在 char-table 未指定任何其他非 nil 值时返回默认值。

Function:  make-char-table subtype &optional init ¶

返回一个新创建的字符表,带有子类型 subtype(一个符号)。 每个元素都初始化为 init,默认为 nil。 创建 char-table 后,您无法更改 char-table 的子类型。

没有参数来指定 char-table 的长度,因为所有 char-tables 都有任何有效字符代码作为索引的空间。

如果 subtype 具有 char-table-extra-slots 符号属性,则指定 char-table 中的额外插槽数。 这应该是 0 到 10 之间的整数; 否则,make-char-table 会引发错误。 如果 subtype 没有 char-table-extra-slots 符号属性(请参阅属性列表),则 char-table 没有额外的插槽。

Function: char-table-p object ¶

如果 object 是 char 表,则此函数返回 t,否则返回 nil。

Function: char-table-subtype char-table ¶

该函数返回 char-table 的子类型符号。

没有特殊的函数可以访问字符表中的默认值。 为此,请使用 char-table-range(见下文)。

Function: char-table-parent char-table ¶

此函数返回 char-table 的父级。 父级总是 nil 或另一个字符表。

Function: set-char-table-parent char-table new-parent ¶

此函数将 char-table 的父级设置为 new-parent。

Function: char-table-extra-slot char-table n ¶

此函数返回字符表的额外槽 n(从零开始)的内容。 字符表中的额外槽数由其子类型决定。

Function: set-char-table-extra-slot char-table n value ¶

此函数将值存储在字符表的额外槽 n(从零开始)中。

char-table 可以为单个字符代码指定一个元素值; 它还可以为整个字符集指定一个值。

Function: char-table-range char-table range ¶

这将返回在 char-table 中为一系列字符范围指定的值。 以下是范围的可能性:

nil

指默认值。

char

指字符 char 的元素(假设 char 是有效的字符代码)。

(from . to)

cons 单元格引用包含范围“[from..to]”中的所有字符。

Function: set-char-table-range char-table range value ¶

此函数设置字符表中字符范围的值。 以下是范围的可能性:

nil

指默认值。

t

指整个范围的字符代码。

char

指字符 char 的元素(假设 char 是有效的字符代码)。

(from . to)

cons 单元格引用包含范围“[from..to]”中的所有字符。

Function: map-char-table function char-table ¶

此函数为 char-table 中具有非 nil 值的每个元素调用其参数函数。 函数调用有两个参数,一个键和一个值。 键是 char-table-range 的可能范围参数——有效字符或 cons 单元格(从 . 到),指定共享相同值的字符范围。 该值是 (char-table-range char-table key) 返回的值。

总的来说,传递给函数的键值对描述了存储在 char-table 中的所有值。

返回值始终为零; 为了使调用 map-char-table 有用,函数应该有副作用。 例如,这里是如何检查语法表的元素:

    (let (accumulator)
	 (map-char-table
	  (lambda (key value)
	    (setq accumulator
		  (cons (list
			 (if (consp key)
			     (list (car key) (cdr key))
			   key)
			 value)
			accumulator)))
	  (syntax-table))
	 accumulator)
    ⇒
    (((2597602 4194303) (2)) ((2597523 2597601) (3))
     ... (65379 (5 . 65378)) (65378 (4 . 65379)) (65377 (1))
     ... (12 (0)) (11 (3)) (10 (12)) (9 (0)) ((0 8) (3)))

6.7 布尔向量

布尔向量很像向量,只是它只存储值 t 和 nil。 如果您尝试将任何非零值存储到布尔向量的元素中,则效果是将 t 存储在那里。 与所有数组一样,布尔向量索引从 0 开始,一旦创建布尔向量,长度就不能更改。 布尔向量在评估时是常数。

有几个函数专门用于布尔向量; 除此之外,您可以使用与其他类型数组相同的函数来操作它们。

Function: make-bool-vector length initial ¶

返回一个新的长度元素的布尔向量,每个元素都初始化为初始值。

Function: bool-vector &rest objects ¶

这个函数创建并返回一个布尔向量,其元素是参数,对象。

Function: bool-vector-p object ¶

如果 object 是布尔向量,则返回 t,否则返回 nil。

还有一些 bool-vector 集合操作函数,描述如下:

Function: bool-vector-exclusive-or a b &optional c ¶

返回布尔向量 a 和 b 的按位异或。 如果给定可选参数 c,则此操作的结果将存储到 c 中。 所有参数都应该是相同长度的布尔向量。

Function: bool-vector-union a b &optional c ¶

返回布尔向量 a 和 b 的按位或。 如果给定可选参数 c,则此操作的结果将存储到 c 中。 所有参数都应该是相同长度的布尔向量。

Function: bool-vector-intersection a b &optional c ¶

返回布尔向量 a 和 b 的按位与。 如果给定可选参数 c,则此操作的结果将存储到 c 中。 所有参数都应该是相同长度的布尔向量。

Function: bool-vector-set-difference a b &optional c ¶

返回 bool 向量 a 和 b 的集合差。 如果给定可选参数 c,则此操作的结果将存储到 c 中。 所有参数都应该是相同长度的布尔向量。

Function: bool-vector-not a &optional b ¶

返回 bool 向量 a 的补集。 如果给定可选参数 b,则此操作的结果将存储到 b 中。 所有参数都应该是相同长度的布尔向量。

Function: bool-vector-subsetp a b ¶

如果 a 中的每个 t 值也是 b 中的 t,则返回 t,否则返回 nil。 所有参数都应该是相同长度的布尔向量。

Function: bool-vector-count-consecutive a b i ¶

返回从 i 开始的相等 b 中连续元素的数量。 a 是一个布尔向量,b 是 t 或 nil,而 i 是 a 的索引。

Function: bool-vector-count-population a ¶

返回布尔向量 a 中为 t 的元素的数量。

打印出来的表格最多可将 8 个布尔值表示为单个字符:

(bool-vector t nil t nil)
     ⇒ #&4"^E"
(bool-vector)
     ⇒ #&0""

您可以使用 vconcat 像其他向量一样打印布尔向量:

(vconcat (bool-vector nil t nil t))
     ⇒ [nil t nil t]

这是另一个创建、检查和更新布尔向量的示例:

(setq bv (make-bool-vector 5 t))
     ⇒ #&5"^_"
(aref bv 1)
     ⇒ t
(aset bv 3 nil)
     ⇒ nil
bv
     ⇒ #&5"^W"

这些结果是有意义的,因为 control-_ 和 control-W 的二进制代码分别是 11111 和 10111。

6.8 管理固定大小的对象环

环是一种固定大小的数据结构,支持插入、删除、旋转和模索引引用和遍历。 ring 包实现了一个高效的环数据结构。 它提供了本节中列出的功能。

请注意,Emacs 中的几个环,例如 kill ring 和 mark ring,实际上是作为简单列表实现的,而不是使用 ring 包; 因此以下功能对它们不起作用。

Function: make-ring size ¶

这将返回一个能够容纳 size 对象的新环。 大小应该是一个整数。

Function: ring-p object ¶

如果对象是环,则返回 t,否则返回 nil。

Function: ring-size ring ¶

这将返回环的最大容量。

Function: ring-length ring ¶

这将返回 ring 当前包含的对象数。 该值永远不会超过 ring-size 返回的值。

Function: ring-elements ring ¶

这将按顺序返回环中对象的列表,最新的在前。

Function: ring-copy ring ¶

这将返回一个新的环,它是环的副本。 新环包含与环相同的 (eq) 对象。

Function: ring-empty-p ring ¶

如果 ring 为空,则返回 t,否则返回 nil。

环中最新的元素始终具有索引 0。更高的索引对应于较旧的元素。 索引以环长度为模计算。 索引 -1 对应于最旧的元素,-2 对应于下一个最旧的元素,依此类推。

Function: ring-ref ring index ¶

这将返回在索引索引处找到的环中的对象。 index 可能为负数或大于环长度。 如果 ring 为空,则 ring-ref 发出错误信号。

Function: ring-insert ring object ¶

这会将对象插入到环中,使其成为最新元素,并返回对象。

如果环已满,插入会删除最旧的元素,为新元素腾出空间。

Function: ring-remove ring &optional index ¶

从环中移除一个对象,并返回该对象。 参数 index 指定要删除的项目; 如果为 nil,则表示删除最旧的项目。 如果 ring 为空,则 ring-remove 会发出错误信号。

Function: ring-insert-at-beginning ring object ¶

这会将对象插入到环中,将其视为最旧的元素。 返回值不重要。

如果环已满,此函数将删除最新的元素,为插入的元素腾出空间。

Function: ring-resize ring size ¶

将环的大小设置为大小。 如果新大小更小,则丢弃环中最旧的项目。

如果您注意不要超过环大小,则可以将环用作先进先出队列。 例如:

(let ((fifo (make-ring 5)))
  (mapc (lambda (obj) (ring-insert fifo obj))
	  '(0 one "two"))
  (list (ring-remove fifo) t
	  (ring-remove fifo) t
	  (ring-remove fifo)))
     ⇒ (0 t one t "two")
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/rookieagle/elisp.git
git@gitee.com:rookieagle/elisp.git
rookieagle
elisp
Elisp
main

搜索帮助