The missing hash table library for Emacs.
Table of Contents
ht-create
(test?)
ht-merge
(&rest tables)
ht-copy
(table)
ht-select
(function table)
ht-reject
(function table)
ht-select-keys
(table keys)
ht-get
(table key default?)
ht-get*
(table &rest keys)
ht-keys
(table)
ht-values
(table)
ht-items
(table)
ht-find
(function table)
ht-size
(table)
ht-set!
(table key value)
ht-update!
(table table)
ht-update-with!
(table key updater default?)
ht-remove!
(table key)
ht-clear!
(table)
ht-reject!
(function table)
ht-map
(function table)
ht-each
(function table)
ht?
(table-or-object)
ht-contains?
(table key)
ht-equal?
(table1 table2)
ht-empty?
(table)
ht->alist
(table)
ht->plist
(table)
ht<-alist
(alist test?)
ht<-plist
(plist test?)
ht
(&rest pairs)
ht-amap
(form table)
ht-aeach
(form table)
Creating a hash table and accessing it:
(require 'ht)
(defun say-hello (name)
(let ((greetings (ht ("Bob" "Hey bob!")
("Chris" "Hi Chris!"))))
(ht-get greetings name "Hello stranger!")))
This could be alternatively written as:
(require 'ht)
(defun say-hello (name)
(let ((greetings (ht-create)))
(ht-set! greetings "Bob" "Hey Bob!")
(ht-set! greetings "Chris" "Hi Chris!")
(ht-get greetings name "Hello stranger!")))
Accessing nested hash tables:
(let ((alphabets (ht ("Greek" (ht (1 (ht ('letter "α")
('name "alpha")))
(2 (ht ('letter "β")
('name "beta")))))
("English" (ht (1 (ht ('letter "a")
('name "A")))
(2 (ht ('letter "b")
('name "B"))))))))
(ht-get* alphabets "Greek" 1 'letter)) ; => "α"
ht-get
and ht-get*
have gv-setters and so will work with setf
:
(let ((table (ht-create)))
(ht-set! table 1 "A"))
is equivalent to
(let ((table (ht-create)))
(setf (ht-get table 1) "A"))
and
(let ((table (ht (1 (ht (2 (ht (3 "three"))))))))
(ht-set! (ht-get (ht-get table 1) 2) 3 :three))
is equivalent to
(let ((table (ht (1 (ht (2 (ht (3 "three"))))))))
(setf (ht-get* table 1 2 3) :three))
Updating values with a function using ht-update-with!
:
(let ((table (ht ("a" (list "a" "b")))))
(ht-update-with!
table "a"
(lambda (list)
(cons "c" list)))
(ht-get table "a")) ; '("c" "a" "b"))
is equivalent to
(let ((table (ht ("a" (list "a" "b")))))
(setf (ht-get table "a")
(cons "c" (ht-get table "a")))
(ht-get table "a")) ; '("c" "a" "b"))
Libraries like s.el (strings) and dash.el (lists) have shown how much nicer Emacs lisp programming can be with good libraries. ht.el aims to similarly simplify working with hash tables.
Common operations with hash tables (e.g. enumerate the keys) are too difficult in Emacs lisp.
ht.el offers:
- A consistent naming scheme (contrast
make-hash-table
withputhash
) - A more natural argument ordering
- Mutation functions always return
nil
- A more comprehensive range of hash table operations, including a
conventional map (
ht-map
returns a list, elisp'smaphash
returns nil).
- kv.el (focuses more on alists)
- mon-hash-utils
ht.el is available on MELPA (recommended) and Marmalade.
Add MELPA to your .emacs.d/init.el:
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
then run M-x package-install <RET> ht <RET>
.
ht.el uses semantic versioning, so an incompatible API change will result in the major version increasing. See CHANGELOG.md for a history of all changes.
M-x ht-run-tests
An alist is an association list, which is a list of pairs. It looks like this:
((key1 . value1)
(key2 . value2)
(key3 . value3))
An alist can also look like this:
((key1 . value1)
(key2 . value2)
(key1 . oldvalue))
A plist is a property list, which is a flat list with an even number of items. It looks like this:
(key1 value1
key2 value2
key3 value3)
Both of these are slow. ht.el provides ht<-alist
and
ht<-plist
to help you convert to hash tables. If you need to
work with an alist or plist, use the functions ht->alist
and
ht->plist
to convert an hash table to those formats.