如何使用 make-array 或 coerce 将列表转换为具有相同输出的 Common Lisp 中的一维数组(向量)?
How to convert a list to a one dimensional array (vector) in Common Lisp having the same output either using make-array or coerce?
我想从一个简单列表转换:
'(1 2 3)
到一维数组(向量):
#(1 2 3)
我发现 this question 类似但没有涵盖这个问题。
我也想办法实现了。不确定它是否是最好的:
CL-USER> (coerce '(1 2 3) 'vector)
#(1 2 3)
CL-USER> (type-of *)
(SIMPLE-VECTOR 3)
我想知道是否可以使用 make-array
来达到相同的结果。我试过了:
CL-USER> (make-array '() :initial-contents '(1 2 3))
#0A(1 2 3)
CL-USER> (type-of *)
(SIMPLE-ARRAY T NIL)
这很接近,但我不明白 #0A(1 2 3)
中的 #0A
。
出于某种我不明白的原因,此输出不适用于进一步的组合,例如 aref
:
CL-USER> (aref #0A(1 2 3) 0)
; Evaluation aborted on #<SIMPLE-ERROR "Wrong number of subscripts, ~W, for array of rank ~W." {1003C07793}>.
是否可以使用make-array
达到与coerce
相同的结果?
这两种方法有什么区别?
其中一个比另一个更快还是更优雅?
COERCE
很好,如果需要,您甚至可以指定元素类型:
USER> (coerce '(1 2 3) '(vector fixnum))
#(1 2 3)
USER> (describe *)
#(1 2 3)
[simple specialized vector]
Element-type: FIXNUM
Length: 3
您可以对 make-array
执行相同的操作,但您需要提供正确的维度。维度参数表示可能的多维数组有多少行、多少列等。它应该是一个列表,但是当你只有一个维度时,它可以只是一个数字。这里的两种形式是等价的:
USER> (make-array 3 :initial-contents '(1 2 3))
#(1 2 3)
USER> (make-array '(3) :initial-contents '(1 2 3))
#(1 2 3)
通常你会打电话给(length list)
。与 coerce
相比的附加值是您可以指定 :fill-pointer
或 :adjustable
参数,这是 coerce
的类型参数无法传达的。
数组的打印表示是#nA()
,其中n
是数组的维数,如果它是向量(n = 1).例如:
USER> (make-array '(10 2) :initial-element 0)
#2A((0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0))
对于给定的维度 n
数组,您可以使用 aref
访问元素,参数与维度一样多,在 row-major 中顺序(与您在 make-array
中指定尺寸的顺序相同)。
USER> (aref * 5 1)
0 (0 bits, #x0, #o0, #b0)
在您的示例中,您定义了一个维度为 0 的数组,因为您将 '()
(a.k.a。只是 ()
或 nil
)写为维度。如果你需要一个盒子来存储单个元素,可以使用这个:
USER> (defparameter *box* (make-array nil :element-type '(mod 8)))
*BOX*
USER> (describe *box*)
#0A0
[simple specialized array]
Element-type: (UNSIGNED-BYTE 4)
Dimensions: NIL
Storage vector: #<(SIMPLE-ARRAY (UNSIGNED-BYTE 4) (1)) {101EA0C59F}>
; No values
USER> (setf (aref *box*) 7)
7 (3 bits, #x7, #o7, #b111)
USER> (incf (aref *box*))
8 (4 bits, #x8, #o10, #b1000)
USER> (aref *box*)
8 (4 bits, #x8, #o10, #b1000)
(可以看到,数组中可以存储的值是upgraded-element-type
对应的值,这里是(unsigned-byte 4)
;例如(setf (aref *box*) (expt 2 16))
发出错误信号)
看起来 :initial-contents
与 :initial-element
的结果相同,因为在您的示例中,零维数组的内容是列表 (1 2 3)
Is one of them faster or more elegant than the other?
我尽量使用 coerce
因为它写起来更短而且看起来更能描述我正在做的事情。我不认为它更快,除非你事先知道列表的长度。
我想从一个简单列表转换:
'(1 2 3)
到一维数组(向量):
#(1 2 3)
我发现 this question 类似但没有涵盖这个问题。
我也想办法实现了。不确定它是否是最好的:
CL-USER> (coerce '(1 2 3) 'vector)
#(1 2 3)
CL-USER> (type-of *)
(SIMPLE-VECTOR 3)
我想知道是否可以使用 make-array
来达到相同的结果。我试过了:
CL-USER> (make-array '() :initial-contents '(1 2 3))
#0A(1 2 3)
CL-USER> (type-of *)
(SIMPLE-ARRAY T NIL)
这很接近,但我不明白 #0A(1 2 3)
中的 #0A
。
出于某种我不明白的原因,此输出不适用于进一步的组合,例如 aref
:
CL-USER> (aref #0A(1 2 3) 0)
; Evaluation aborted on #<SIMPLE-ERROR "Wrong number of subscripts, ~W, for array of rank ~W." {1003C07793}>.
是否可以使用make-array
达到与coerce
相同的结果?
这两种方法有什么区别?
其中一个比另一个更快还是更优雅?
COERCE
很好,如果需要,您甚至可以指定元素类型:
USER> (coerce '(1 2 3) '(vector fixnum))
#(1 2 3)
USER> (describe *)
#(1 2 3)
[simple specialized vector]
Element-type: FIXNUM
Length: 3
您可以对 make-array
执行相同的操作,但您需要提供正确的维度。维度参数表示可能的多维数组有多少行、多少列等。它应该是一个列表,但是当你只有一个维度时,它可以只是一个数字。这里的两种形式是等价的:
USER> (make-array 3 :initial-contents '(1 2 3))
#(1 2 3)
USER> (make-array '(3) :initial-contents '(1 2 3))
#(1 2 3)
通常你会打电话给(length list)
。与 coerce
相比的附加值是您可以指定 :fill-pointer
或 :adjustable
参数,这是 coerce
的类型参数无法传达的。
数组的打印表示是#nA()
,其中n
是数组的维数,如果它是向量(n = 1).例如:
USER> (make-array '(10 2) :initial-element 0)
#2A((0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0) (0 0))
对于给定的维度 n
数组,您可以使用 aref
访问元素,参数与维度一样多,在 row-major 中顺序(与您在 make-array
中指定尺寸的顺序相同)。
USER> (aref * 5 1)
0 (0 bits, #x0, #o0, #b0)
在您的示例中,您定义了一个维度为 0 的数组,因为您将 '()
(a.k.a。只是 ()
或 nil
)写为维度。如果你需要一个盒子来存储单个元素,可以使用这个:
USER> (defparameter *box* (make-array nil :element-type '(mod 8)))
*BOX*
USER> (describe *box*)
#0A0
[simple specialized array]
Element-type: (UNSIGNED-BYTE 4)
Dimensions: NIL
Storage vector: #<(SIMPLE-ARRAY (UNSIGNED-BYTE 4) (1)) {101EA0C59F}>
; No values
USER> (setf (aref *box*) 7)
7 (3 bits, #x7, #o7, #b111)
USER> (incf (aref *box*))
8 (4 bits, #x8, #o10, #b1000)
USER> (aref *box*)
8 (4 bits, #x8, #o10, #b1000)
(可以看到,数组中可以存储的值是upgraded-element-type
对应的值,这里是(unsigned-byte 4)
;例如(setf (aref *box*) (expt 2 16))
发出错误信号)
看起来 :initial-contents
与 :initial-element
的结果相同,因为在您的示例中,零维数组的内容是列表 (1 2 3)
Is one of them faster or more elegant than the other?
我尽量使用 coerce
因为它写起来更短而且看起来更能描述我正在做的事情。我不认为它更快,除非你事先知道列表的长度。