emacsのlispでハッシュhashを使う。

| コメント(0) | トラックバック(0)

elispのhashの使い方をメモ公開

lispで設定情報を格納した変数を作りたいな、 しかしlistはデータ重複するしな・・・・ と思ったので参考まで。

ハッシュ(hash)とは

  • メリット

    • リストと違いデータの重複は防げる
    • キーから簡単にデータを引っ張れる
  • デメリット

    • 操作の関数がすくない?ので使い方が面倒?

処理速度は検証していないので不明

検証環境

  • CentOS release 6.2 (Final)
  • GNU Emacs 23.4.1

ハッシュテーブルの作成

;;  :test キー検索する際のメソッド equalがいろんなケースで検索できるので便利
(setq hash (make-hash-table :test 'equal))
    ;=>   #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ( ...))


;; 作成と同時にデータを入れる方法
(setq hash_in_data
      #s(hash-table test equal
           data( "a" "hoge"  "b" "fuga" "c" "ccc")))
    ;=> #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ("a" "hoge" "b" "fuga" "c" "ccc" ...))

;;dataの部分に指定する。  "a"の1番目key "hoge"の2番目がval

puthash ハッシュに値を入れる

(puthash "a" 1 hash)
    ;=> 1
(puthash "b" 2 hash)
    ;=> 2
(puthash "c" 3 hash)
    ;=> 3
(puthash "d" 4 hash)
    ;=> 4

gethash ハッシュから値を取り出す

(gethash "a" hash)
    ;=> 1
(gethash "b" hash)
    ;=> 2
(gethash "a" hash_in_data)
    ;=>"hoge"
(gethash "b" hash_in_data)
    ;=>"fuga"


;存在しなければ nil
(gethash "x" hash)
    ;=> nil

;;## remhash ハッシュの要素を削除
(remhash "d" hash)
    ;=> nil

(gethash "d" hash)
    ;=> nil

ハッシュをdefvarでグローバル化する

(defvar g_hash 
      #s(hash-table test equal
           data( "ruby-mode" "ruby"
                 "sh-mode" "bash")))
    ;=> g_hash

g_hash
    ;=> #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ("ruby-mode" "ruby" "sh-mode" "bash" ...))


(defun  foo ()
  (gethash "ruby-mode" g_hash)
)
    ;=>foo

(foo)
    ;=> "ruby"

これで関数内部でhash情報が簡単に取り出せるようになった。

ハッシュの繰り返し処理

; cl関数を使う
(require 'cl)

;; for ハッシュキー begin the hash-keys of  ハッシュ変数
(loop for key being the hash-keys of hash
          do (insert key " " ))
    ;=> a b c d nil

;; 値をとりだすには  using (hash-values 値)  をつける
(loop for key being the hash-keys of hash using (hash-values val)
          do (insert key " =>  " (number-to-string val) ",\n" ))
    ;=> a =>  1,
    ;=> b =>  2,
    ;=> c =>  3,
    ;=> d =>  4,
    ;=> nil


;; ついでにハッシュの中身確認用に関数化
(defun dump-hash (hash)
  (with-temp-buffer
    (loop for key being the hash-keys of hash using (hash-values val)
        do (insert (format "%s" key ) " =>  "  (format "%s" val) ",\n" ))
    (buffer-string))

)

(dump-hash hash)
    ;=> "a =>  1,
    ;=> b =>  2,
    ;=> c =>  3,
    ;=> d =>  4,
    ;=> "

copy-hash-table ハッシュそのものをコピー

(setq cp_hash  (copy-hash-table hash))
    ;=> #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ("a" 3 "b" 100 ...))

clrhash ハッシュの値を全削除

(clrhash cp_hash)
    ;=> #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ( ...))


(gethash "a" cp_hash)
    ;=> nil

ハッシュの結合

;; 自作関数しかなさそう?
(defun append-hash (hash &rest rhash)
  (setq res_hash (copy-hash-table hash ))
  (dolist (var_hash rhash)
    (loop for key being the hash-keys of var_hash using (hash-values val)
          do (puthash key val res_hash)))
res_hash)

(setq a_hash #s(hash-table test equal data( "a" "hoge"  "b" "fuga" "c" "ccc")))
(setq b_hash #s(hash-table test equal data( "a" "hoge"  "d" "ddd" "e" "eeee")))


(setq ap_hash (append-hash a_hash b_hash))
     ;=> #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ("a" "hoge" "b" "fuga" "c" "ccc" "d" "ddd" "e" "eeee" ...))

ap_hash
     ;=> #s(hash-table size 65 test equal rehash-size 1.5 rehash-threshold 0.8 data ("a" "hoge" "b" "fuga" "c" "ccc" "d" "ddd" "e" "eeee" ...))

(gethash "c" ap_hash)
     ;=> "ccc"

(gethash "e" ap_hash)
     ;=> "eeee"

おわり

簡単な設定情報だったら、hashを使えばデータの重複なく操作可能とわかりました。 しかし、多重配列みないな形にしたい!

と言う訳で次回予定は:hashの多重配列もどきを作る

※ 2012/03/27更新、次回のリンク追加

elispでhashの多重配列もどきを作っていたら、オレオレライブラリになった件

参考ページ

本家マニュアル

関連記事

トラックバック(0)

トラックバックURL: http://mukaer.com/cgi-bin/mt/mt-tb.cgi/67

コメントする

PR

PR





検索

Loading

メニュー

twitter