Emacs Lisp Hash-table

Emacs Lisp では、(require 'cl) によって Common Lisp の一部の機能が使える。
その中の loop マクロは、ドキュメントには書かれていないようだがちゃんと Hash-table のトラバースに使える。

以下は、ハッシュテーブルを使って、バッファー内の文字の使用頻度を調べるもの。

  • make-hash-table でハッシュテーブルを作成
  • puthash で値を設定
  • gethash で値を取得
  • loop .. being the hash-keys ... でハッシュテーブルのすべてのキー、値を処理

Emacs のバッファー内のすべての文字を効率的に処理する方法が良くわからなかったので、
buffer-substring-no-properties で全部取得した上で、 vconcat でベクターにしてみた。

(defun char-frequency (&optional vec)
  "return new hash-table which contains char(integer) => frequency for current buffer or vector vec"
  (interactive)
  (if (null vec)
      (char-frequency (vconcat (buffer-substring-no-properties (point-min) (point-max))))
    (let ((ht (make-hash-table)))
      (loop for c across vec do (puthash c (1+ (or (gethash c ht) 0)) ht))
      ht)))

(defun test-freq ()
  "return alist of frequency character"
  (let ((ht (char-frequency)))
    (let ((str-freq
	   (loop for c being the hash-keys in ht using (hash-value f)
		 collect (cons f (char-to-string c)))))
      (sort str-freq (lambda (a b) (> (car a) (car b)))))))