逆引きxyzzy lisp(配列、ハッシュ、キュー) - circleratio/xyzzy GitHub Wiki
(make-array '(3 2))
=> #2A((nil nil) (nil nil) (nil nil))
初期値を設定するには,initial-element(すべての要素に同じ値を設定)または initial-contents (要素ごとに異なる値を設定) オプションを使う.
(make-array '(3 2) :initial-element 0)
=> #2A((0 0) (0 0) (0 0))
(make-array '(2 3) :initial-contents '((a b c) (d e f)))
=> #2A((a b c) (d e f))
直接数値を書くのであれば、次のようにすればよい。
#(1 2 3)
=> #(1 2 3)
この操作は破壊的なので注意.
(setq mat (make-array '(3 2)))
=> #2A((nil nil) (nil nil) (nil nil))
(setf (aref mat 2 1) 1)
=> 1
mat
=> #2A((nil nil) (nil nil) (nil 1))
(setq mat (make-array '(3 2)))
=> #2A((nil nil) (nil nil) (nil nil))
(setf (aref mat 1 0) 10)
=> 10
mat
=> #2A((nil nil) (10 nil) (nil nil))
(aref mat 1 0)
=> 10
次元ごとに調べることもできるし(array-dimension)、全部まとめてリストで求めることもできる。
(setq mat (make-array '(2 3) :initial-contents '((a b c) (d e f))))
=> #2A((a b c) (d e f))
(array-dimension mat 0)
=> 2
(array-dimension mat 1)
=> 3
(array-dimensions mat)
=> (2 3)
要素数の合計を調べるには array-total-size を使う。
(array-total-size mat)
=> 6
作成は make-hash-table, 削除は clrhash を使う.
(setq hash (make-hash-table :test #'equal))
=> #<hashtable 46666404>
(clrhash hash)
=> #<hashtable 46666404>
値を追加するには setf, 取得するには gethash, 削除するには remhash を使う.
(setf (gethash "abc" hash) 100)
=> 100
(gethash "abc" hash)
=> 100
(remhash "abc" hash)
=> t
(gethash "abc" hash)
=> nil
gethash が nil を返すかどうかで判定する.
(defun hash-key-exist-p (key hash)
(if (gethash key hash) t nil))
使用例は以下.
(setq hash (make-hash-table :test #'equal))
=> #<hashtable 46666404>
(setf (gethash "abc" hash) 100)
=> 100
(hash-key-exist-p "abc" hash)
=> t
(hash-key-exist-p "def" hash)
=> nil
maphash を使う.
(setq hash (make-hash-table :test #'equal))
=> #<hashtable 46666380>
(setf (gethash "a" hash) 100)
(setf (gethash "b" hash) 200)
(setf (gethash "c" hash) 300)
(maphash #'(lambda (key val) (format t "key = ~A, val = ~A~%" key val)) hash)
=> key = a, val = 100
key = b, val = 200
key = c, val = 300
xyzzy lisp はハッシュは read/write してくれない(CLでは実装依存)ので,自分で書く.
(defun dump-hash (hash file)
(with-open-file (stream file :direction :output :if-exists :supersede)
(write (let ((alist nil))
(maphash #'(lambda (key val)
(pushnew (cons key val) alist))
hash)
alist) :stream stream)))
(defun restore-hash (file)
(let ((alist (with-open-file
(stream file :direction :input)
(read stream)))
(hash (make-hash-table :test #'equal)))
(list-to-hash hash alist)))
(defun list-to-hash (hash alist)
(let* ((p (car alist)) (key (car p)) (val (cdr p)))
(if (equal p nil)
hash
(progn
(setf (gethash key hash) val)
(list-to-hash hash (cdr alist))))))
使い方は下記.
(setq hash (make-hash-table :test #'equal))
(setf (gethash "a" hash) 100)
(setf (gethash "b" hash) 200)
(setf (gethash "c" hash) 300)
(dump-hash hash "c:/temp/hash.dmp")
=> (("c" . 300) ("b" . 200) ("a" . 100))
(setq hash (restore-hash "c:/temp/hash.dmp"))
=> #<hashtable 46666284>
(gethash "b" hash)
=> 200
要素数を数えるには hash-table-count を使う。
(hash-table-count hash)
=> 1
ハッシュテーブルの大きさを調べるには hash-table-size を使う。
(hash-table-size hash)
=> 17
(defun hash-keys (hash)
(let ((keys))
(maphash #'(lambda (key val)
(setq keys (cons key keys))) hash)
keys))
(defun hash-values (hash)
(let ((vals))
(maphash #'(lambda (key val)
(setq vals (cons val vals))) hash)
vals))
(defun hash-to-alist (hash)
(let ((alist))
(maphash #'(lambda (key val)
(setq alist (acons key val alist))) hash)
alist))
使用例:
(setq hash (make-hash-table :test #'equal))
=> #<hashtable 46666428>
(setf (gethash "a" hash) 100)
(setf (gethash "b" hash) 200)
(setf (gethash "c" hash) 300)
(hash-keys hash)
=> ("c" "b" "a")
(hash-values hash)
=> (300 200 100)
(setq al (hash-to-alist hash))
=> (("c" . 300) ("b" . 200) ("a" . 100))
(assoc "a" al :test #'equal)
=> ("a" . 100)
逆引きxyzzy lisp(リスト)の項で定義した sort-alist 関数を活用する.
(defun sort-alist (alist cmp-car cmp-cdr)
(labels ((compare-alist (e1 e2 cmp-car cmp-cdr)
(let ((car1 (car e1))
(car2 (car e2))
(cdr1 (cdr e1))
(cdr2 (cdr e2)))
(if (equalp cdr1 cdr2)
(funcall cmp-car car1 car2)
(funcall cmp-cdr cdr1 cdr2)))))
(sort alist (lambda (e1 e2)
(compare-alist e1 e2 cmp-car cmp-cdr)))))
(defun hash-to-alist (hash)
(let ((alist))
(maphash #'(lambda (key val)
(setq alist (acons key val alist))) hash)
alist))
(defun sort-hash (hash cmp-car cmp-cdr)
(sort-alist (hash-to-alist hash) cmp-car cmp-cdr))
使用例:
(setq hash (make-hash-table :test #'equal))
(setf (gethash "abc" hash) 100)
(setf (gethash "bca" hash) 200)
(setf (gethash "cab" hash) 300)
(setf (gethash "acb" hash) 200)
(setf (gethash "bac" hash) 100)
(setf (gethash "cba" hash) 500)
(sort-hash hash #'string< #'>)
=> (("cba" . 500) ("cab" . 300) ("acb" . 200) ("bca" . 200) ("abc" . 100) ("bac" . 100))
「ハッシュをリストに変換する」の項で定義した hash-keys 関数を使う.
(setq hash (make-hash-table :test #'equal))
(setf (gethash "abc" hash) 100)
(setf (gethash "bca" hash) 200)
(setf (gethash "cab" hash) 300)
(setf (gethash "acb" hash) 200)
(setf (gethash "bac" hash) 100)
(setf (gethash "cba" hash) 500)
(defun hash-keys (hash)
(let ((keys))
(maphash #'(lambda (key val)
(setq keys (cons key keys))) hash)
keys))
=> hash-keys
(hash-keys hash)
=> ("cab" "abc" "bca" "bac" "acb" "cba")
(let ((keys (hash-keys hash)))
(nth (random (length keys)) keys))
=> "acb"
(gethash
(let ((keys (hash-keys hash)))
(nth (random (length keys)) keys))
hash)
=> 200
t
(defun alist-to-hash (alist)
(let ((hash (make-hash-table :test #'equal)))
(map 'list (lambda (x) (setf (gethash (car x) hash) (cdr x))) alist)
hash))
使用例:
(setq alist '(("cba" . 500) ("cab" . 300) ("acb" . 200) ("bca" . 200) ("abc" . 100) ("bac" . 100)))
=> (("cba" . 500) ("cab" . 300) ("acb" . 200) ("bca" . 200) ("abc" . 100) ("bac" . 100))
(setq h (alist-to-hash '(("cba" . 500) ("cab" . 300) ("acb" . 200) ("bca" . 200) ("abc" . 100) ("bac" . 100))))
=> #<hashtable 68489820>
(gethash "acb" h)
=> 200
「ハッシュを連想リストに変換⇒連想リストをマージ⇒連想リストをハッシュに変換」の手順で行う.
(defun hash-to-alist (hash)
(let ((alist))
(maphash #'(lambda (key val)
(setq alist (acons key val alist))) hash)
alist))
=> hash-to-alist
(defun alist-to-hash (alist)
(let ((hash (make-hash-table :test #'equal)))
(map 'list (lambda (x) (setf (gethash (car x) hash) (cdr x))) alist)
hash))
=> alist-to-hash
(defun merge-hash (hash1 hash2)
(alist-to-hash
(append (hash-to-alist hash1) (hash-to-alist hash2))))
=> merge-hash
使用例:
(setq hash1 (make-hash-table :test #'equal))
(setq hash2 (make-hash-table :test #'equal))
(setf (gethash "abc" hash1) 100)
(setf (gethash "bca" hash1) 200)
(setf (gethash "cab" hash1) 300)
(setf (gethash "acb" hash2) 200)
(setf (gethash "bac" hash2) 100)
(setf (gethash "cba" hash2) 500)
(hash-to-alist hash1)
=> (("cab" . 300) ("abc" . 100) ("bca" . 200))
(hash-to-alist hash2)
=> (("bac" . 100) ("cba" . 500) ("acb" . 200))
(setq h (merge-hash hash1 hash2))
=> #<hashtable 67048076>
(gethash "cab" h)
=> 300
t
(gethash "bac" h)
=> 100
t
(defstruct Queue
(front nil)
(rear nil))
=> #<structure-definition: Queue>
(defun enqueue (queue item)
(let ((cell (list item)))
(if (Queue-front queue)
(setf (cdr (Queue-rear queue)) cell)
(setf (Queue-front queue) cell))
(setf (Queue-rear queue) cell)))
(defun dequeue (queue)
(if (Queue-front queue)
(prog1 (pop (Queue-front queue))
(unless (Queue-front queue)
(setf (Queue-rear queue) nil)))))
(setq *queue* (make-Queue))
=> #S(Queue front nil rear nil)
(dotimes (x 5) (enqueue *queue* x))
=> nil
*queue*
=> #S(Queue front (0 1 2 3 . #1=(4)) rear #1#)
(dequeue *queue*)
=> 0
(dequeue *queue*)
=> 1
*queue*
=> #S(Queue front (2 3 . #1=(4)) rear #1#)