删除函数对数组有什么作用?

Con*_*zer 5 sbcl common-lisp

我试图使用deleteCommon Lisp (SBCL) 中的函数从数组中删除一个元素,但注意到在调用以下命令后,该数组的所有索引仍然存在((length arr)数组上的返回值不变)delete

(defparameter *x* (make-array 3 :initial-contents (list 13 26 39)))
*x* ; #(13 26 39)
(delete 26 *x* :test #'equal) ; #(13 39)

*x* ; #(13 39 39)
(length *x*) ; 3
Run Code Online (Sandbox Code Playgroud)

我假设*X*调用后仍然可以访问 的第二个元素delete,因为数组是连续的内存块,其中索引无法在不创建新数组的情况下“删除”。

我的困惑来自于setf与 的结合使用delete。这仅允许用户访问不受以下影响的元素delete

(defparameter *y* (make-array 3 :initial-contents (list 13 26 39)))
*y* ; #(13 26 39)
(setf *y* (delete 26 *y* :test #'equal)) ; #(13 39)

*y* ; #(13 39)
(length *y*) ; 2
Run Code Online (Sandbox Code Playgroud)

这是否意味着delete在数组上调用时返回一个新数组?或者调用是否setf创建一个新数组,以便(setf (delete ...))有效地执行与 相同的操作(setf (remove ...))?或者是*Y*从上面一直指向同一个数组,只是第二个元素在幕后以某种方式被“忽略”?

Rai*_*wig 6

如果您阅读 Common Lisp 标准(通常是 Common Lisp HyperSpec),那么它会说:

删除项目序列&key from-end test test-not start end count key => 结果序列

...

delete、delete-if 和delete-if-not 分别类似于remove、remove-if 和remove-if-not,但它们可能会修改顺序。

sequencevector是和的超类型list。因此该函数delete适用于向量和列表。

delete item sequence表示所需的参数。

but they may modify sequencethen 意味着该函数可以修改作为参数提供的原始序列。可能修改 意味着实现的行为可能有所不同。

但无论如何你都需要使用返回的结果序列。这也相对容易记住,因为许多(但不是全部)函数通常返回结果,并且最好根据计算结果来思考,而不是作为具有副作用的过程。

请注意,Common Lisp 中的向量是可变对象。人们可以更改其内容,而无需分配新对象。另请注意:Common Lisp 提供了可能修改参数对象的破坏性函数。对于某些函数,该行为是预期的,而对于某些函数,它们是不应使用的副作用。delete就是这样的后一个函数:参数序列可以更改并且该对象不应再使用。

示例1:

(defparameter *x* (make-array 3 :initial-contents (list 13 26 39)))
Run Code Online (Sandbox Code Playgroud)

上面使用提供的内容创建了一个长度为 3 的矢量对象。该变量*x*指向该对象。

*x* ; #(13 26 39)
Run Code Online (Sandbox Code Playgroud)

上图:变量*x*仍然指向最初创建的对象。

(delete 26 *x* :test #'equal) ; #(13 39)
Run Code Online (Sandbox Code Playgroud)

上图:#(13 39)从调用中返回delete。该值未被使用,只是返回。该变量*x*仍然指向最初创建的向量对象。该对象可能已被更改。

*x* ; #(13 39 39)
Run Code Online (Sandbox Code Playgroud)

上图:变量*x*仍然指向最初创建的对象。该对象已被调用破坏性地更改delete

(length *x*) ; 3
Run Code Online (Sandbox Code Playgroud)

上图:变量*x*仍然指向最初创建的对象。它的长度仍然是3。

示例2:

(defparameter *y* (make-array 3 :initial-contents (list 13 26 39)))
Run Code Online (Sandbox Code Playgroud)

上面使用提供的内容创建了一个长度为 3 的矢量对象。该变量*y*指向该对象。

*y* ; #(13 26 39)
Run Code Online (Sandbox Code Playgroud)

上图:变量*y*仍然指向最初创建的对象。

(setf *y* (delete 26 *y* :test #'equal)) ; #(13 39)
Run Code Online (Sandbox Code Playgroud)

上图:变量*y*被设置为调用返回的对象delete#(13 39)

*y* ; #(13 39)
Run Code Online (Sandbox Code Playgroud)

上图:变量*y*指向delete返回的新对象。

(length *y*) ; 2
Run Code Online (Sandbox Code Playgroud)

上图:变量*y*仍然指向delete返回的新对象。该物体的长度为 2。