;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; This file is part of AIslash.
;
; AIslash is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; AIslash is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with AIslash. If not, see
You can run over lists with dolist: ;
;(dolist (i 1000) ; (print i) ;;Why can't you run over hash tables the same way? ;
E.g. print every key value in a hash table ;
;(dohash (k v h) ; (format t "~a = ~a~%" k v)) ;;
Code: ;
(defmacro dohash ((key value hash &optional end) &body body) `(progn (maphash #'(lambda (,key ,value) ,@body) ,hash) ,end)) ;
Short cut: just access the kyes or values:
(defmacro dovalues ((value hash &optional end) &body body) (let ((key (gensym))) `(progn (maphash #'(lambda (,key ,value) ,@body) ,hash) ,end))) (defmacro dokeys ((key hash &optional end) &body body) (let ((value (gensym))) `(progn (maphash #'(lambda (,key ,value) ,@body) ,hash) ,end))) ;
Q: why gensym? Hint: name collision within @body. ;
(dohash (k v h) (format t "~a = ~a~%" k v)) is all very well ; but what does a real pretty print for a hash table look like? ;
(defun showh (h &key (indent 0) (stream t) (before "") (after "") (if-empty "empty") (show #'(lambda (x) (format stream "~a~a = ~a~%" (nchars indent) (first x) (rest x)))) (lt #'lt)) (if (zerop (hash-table-count h)) (format stream "~a~a~a" before if-empty after) (let (l) (format stream "~a" before) (maphash #'(lambda (k v) (push (cons k v) l)) h) (mapc show (sort l #'(lambda (a b) (funcall lt (car a) (car b))))) (format stream "~a" after) h))) ;;
If that is too complex, then lets look at an example: ;
(deftest test-showh () (let ((h (make-hash-table))) (dolist (one '(apple pear banana)) (setf (gethash (length (string one)) h) one)) (check (samep (with-output-to-string (s) (showh h :stream s)) "4 = PEAR 5 = APPLE 6 = BANANA")))) ;;
(By the same, samep is a very relaxed string comparison ; operator. It ignores all white space- which means that a one space ; typo in the test case does not wreck the test. ;
And here's an example for do-values ;
(deftest test-dovalues () (let (all (h (make-hash-table))) (dolist (one '(apple pear banana)) (setf (gethash (length (string one)) h) one)) (dovalues (value h) (push value all)) (check (equal '(banana pear apple) all)))) ;;
(defun keys2sorted-alist (h ranker) (labels ((car-string-lessp (x y) (string-lessp (rest x) (rest y)))) (let (all (n -1)) (dohash (key value h) (push (cons key (format nil (if (numberp key) ranker "~a") key)) all)) (mapcar #'(lambda (one) `(,(first one) . ,(incf n))) (sort all #'car-string-lessp))))) (defmethod print-object ((object hash-table) stream) (format stream "#" (hash-table-count object))) ;