hash table操作めも
要素を引っ張り出すための関数&マクロのメモ。
;; 適当なサンプルデータ CL-USER> (setq ht (make-hash-table)) #S(HASH-TABLE :TEST EXT:FASTHASH-EQL) CL-USER> (dolist (x (coerce "my lisp !" 'list)) (setf (gethash x ht) (char-code x)) )
loop マクロ
loop言語って複雑すぎてすぐ忘れちゃうなぁ。
毎回仕様書を読んでいる気がするでごあす。
CL-USER> (loop for key being each hash-key in ht using (hash-value value) collect (cons key value)) => ((#\! . 33) (#\p . 112) (#\s . 115) (#\i . 105) (#\l . 108) (#\ . 32) (#\y . 121) (#\m . 109))
maphash
値は返してくれないようだ。(戻り値は常にnil)
CL-USER> (let (acc) (maphash #'(lambda (k v) (push (cons k v) acc)) ht) (nreverse acc)) => ((#\! . 33) (#\p . 112) (#\s . 115) (#\i . 105) (#\l . 108) (#\ . 32) (#\y . 121) (#\m . 109))
hash-tableの順序なんて気にかける必要もないけど、一応↑のものと結果を合わせるためにnreverseしております。
with-hash-table-iterator マクロ
大体はmaphashでことは済むと思うけど、このようなマクロも用意されている。
CL-USER> (let (acc) (with-hash-table-iterator (iter ht) (loop (multiple-value-bind (has-next? k v) (iter) (unless has-next? (return)) (push (cons k v) acc) ))) (nreverse acc)) => ((#\! . 33) (#\p . 112) (#\s . 115) (#\i . 105) (#\l . 108) (#\ . 32) (#\y . 121) (#\m . 109))
第一引数で名前を決めると、その変数に関数を代入してくれる・・・
と思っていたのだけど、そういえばiterをfuncallしなくても使えてるよな、ローカル関数でも定義してるのかな?と思ってマクロを展開してみました。
CL-USER> (macroexpand '(with-hash-table-iterator (iter ht) 'end)) ;; (LET ((#:G4483 (SYSTEM::HASH-TABLE-ITERATOR HT))) ;; (MACROLET ((ITER NIL '(SYSTEM::HASH-TABLE-ITERATE #:G4483))) 'END)) => T
macrolet使ってるそうです。(結構どうでもいい)