make-array, fill-pointer, vector
make-arrayのfill-pointerって何に使うの?死ぬの?と思ってたけど、vectorをスタックのように扱う際に力を発揮するんですね。
しかしmake-array関数が思ったより複雑なので日記にメモ化しましょうという。
まずは基本的な使い方
; tを渡すと:fill-pointerは3(vectorのサイズ)になる ; :fill-pointerを指定するとvector-push,vector-popなどの関数が使えるようになる CL-USER> (make-array 3 :fill-pointer t) #(NIL NIL NIL) ; 0〜3の間で指定することも可能。ポインタが0なのでスタックが見かけ上カラになる ; ただし消えるわけではなく見えないだけ(後述) CL-USER> (setq s (make-array 3 :fill-pointer 0)) #() CL-USER> (fill-pointer s) 0 ; スタックポインタを1にすると0番目の要素だけ見える CL-USER> (setq s (make-array 5 :fill-pointer 1 :initial-element 'x)) #(X) CL-USER> (vector-push 'one s) 1 CL-USER> (vector-push 'two s) 2 ; pushの戻り値は要素のnew-index CL-USER> (elt s (vector-push 'three s)) THREE CL-USER> s #(X ONE TWO THREE) ; :fill-pointerはsetfで操作可能 CL-USER> (setf (fill-pointer s) 5) 5 ; すると見えてなかっただけの最後の要素が出現 CL-USER> s #(X ONE TWO THREE X)
入れすぎ出しすぎの場合
CL-USER> (setq s (make-array 3 :fill-pointer 0)) #() CL-USER> (vector-push 1 s) 0 CL-USER> (vector-push 2 s) 1 CL-USER> (vector-push 3 s) 2 CL-USER> (vector-push 4 s) NIL CL-USER> s #(1 2 3) CL-USER> (vector-pop s) 3 CL-USER> (vector-pop s) 2 CL-USER> (vector-pop s) 1 CL-USER> (vector-pop s) ; Evaluation aborted ;; VECTOR-POP: #() has length zero ; ポインタがずれただけであって、popしても削除はされてない CL-USER> (setf (fill-pointer s) 3) 3 CL-USER> s #(1 2 3)
出しすぎはエラーになるのでfill-pointerやlengthを確認しておく必要がある。
make-arrayで:adjustableにtを与えるとスタックが可変サイズになる。
CL-USER> (setq s (make-array 3 :fill-pointer t :adjustable t)) ;←ここ #(NIL NIL NIL) CL-USER> (vector-push 1 s) NIL ; 通常のpushでは押し込めない CL-USER> s #(NIL NIL NIL) ; vector-push-extend を利用すると・・・ CL-USER> (vector-push-extend 2 s) 3 CL-USER> s #(NIL NIL NIL 2)
element-typeをcharacterにすると(デフォルトはt)文字列が対象になる
CL-USER> (setq s (make-array 3 :element-type 'character :fill-pointer t :initial-element #\z)) "zzz" CL-USER> (vector-pop s) #\z CL-USER> (vector-push #\y s) 2 CL-USER> s "zzy" CL-USER> (array-element-type s) CHARACTER
特に意味はない
CL-USER> (setq s (make-array 12 :fill-pointer 4 :initial-contents "herro, world" :element-type 'character)) "herr" CL-USER> (vector-pop s) #\r CL-USER> (vector-pop s) #\r CL-USER> s "he" CL-USER> (vector-push #\l s) 2 CL-USER> (vector-push #\l s) 3 CL-USER> s "hell" CL-USER> (setf (fill-pointer s) 12) 12 CL-USER> s "hello, world"
:displaced-to
make-arrayの:displaced-toを初めて知った。
CL-USER> (setq x (vector 1 2 3 4 5 6)) #(1 2 3 4 5 6) ; 一次元を二次元に CL-USER> (make-array '(2 3) :displaced-to x) #2A((1 2 3) (4 5 6)) ; 括弧まみれの刑 CL-USER> (make-array '(2 3 1 1 1) :displaced-to x) #5A(((((1))) (((2))) (((3)))) ((((4))) (((5))) (((6))))) ; 三次元を一次元に CL-USER> (setq x (make-array '(2 3 2) :initial-element 0)) #3A(((0 0) (0 0) (0 0)) ((0 0) (0 0) (0 0))) CL-USER> (make-array 12 :displaced-to x) #(0 0 0 0 0 0 0 0 0 0 ...) ; 減る分には問題ないみたい CL-USER> (make-array 3 :displaced-to x) #(0 0 0)