Giter Site home page Giter Site logo

ht.el's Introduction

ht.el

The missing hash table library for Emacs.

MELPA MELPA Stable

Table of Contents

Functions

Return a hash table

  • ht-create (test?)
  • ht-merge (&rest tables)
  • ht-copy (table)
  • ht-select (function table)
  • ht-reject (function table)
  • ht-select-keys (table keys)

Accessing the hash table

  • 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)

Mutating the hash 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)

Iterating over the hash table

  • ht-map (function table)
  • ht-each (function table)

Predicates

  • ht? (table-or-object)
  • ht-contains? (table key)
  • ht-equal? (table1 table2)
  • ht-empty? (table)

Converting from a hash table

  • ht->alist (table)
  • ht->plist (table)

Converting to a hash table

  • ht<-alist (alist test?)
  • ht<-plist (plist test?)

Macros

Returning a hash table

  • ht (&rest pairs)

Iterating over the hash table (anaphoric)

  • ht-amap (form table)
  • ht-aeach (form table)

Examples

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"))

Why?

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 with puthash)
  • 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's maphash returns nil).

Similar libraries

Installation

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>.

Changelog

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.

Running tests

M-x ht-run-tests

What's an alist/plist?

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.

ht.el's People

Contributors

alexander-miller avatar alphapapa avatar cireu avatar doublep avatar garaud avatar kisaragi-hiu avatar miciah avatar rejeep avatar rolpereira avatar sdwolfz avatar sillykelvin avatar swiftlawngnome avatar syohex avatar tarsius avatar wilfred avatar xiongtx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

ht.el's Issues

Add LICENSE file

Hi! Thanks for your maintenance.
There is no LICENSE file though the header says it is under GPLv3+, so it should be added.
I will make PR if you need.

Thanks!

Last non-melpa release was a long time ago

This makes it hard for other packages to accurately state their dependencies---for instance, /kelvinh/orgpage states that it needs ht-1.5 (the last released version), but, in fact, it's not actually compatible.

All that would be required is adding some tags here on github, and melpa-stable would pick the changes up in pretty short order.

ht-set! should return the assigned value

To follow the principle of least suprise, ht-set! should return the assigned value, like puthash, setq, setf, etc.
I've been bitten a few times by this omission. (And consequently had to replace ht-set! with puthash.)

Implement a select-keys function like clojure

Hi,
I didn't find a function which can return a new has-table from a specific selected keys. You could use this function like:

(ht-select-keys table '(:key1 :key2))

See also the select-keys clojure function
I've already a draft implementation of a such function. I'll pull request it as soon as possible.

Cheers,
Damien

Can't install ht

I've followed your install instructions, but ht doesn't show up as an install option on list-packages, nor when doing package-install. Tried on my configuration and a clean emacs -Q and ht is simply not offered. Tried on 29.2 and 28.2.

Release version

It's been three years since the last release of ht.el. It might be cool to have a new release at some point, for the sake of Melpa Stable as well as for Spacemacs (which ships ht.el as part of the distribution).

Several functions lead to invocation error

Hi,

I am trying your mustache.el, and then I find your handy ht.el, but when I am trying it, I find some errors, assume we have following testing code:

(setq table (ht ("a" "A")
                ("b" "B")))

(ht-keys table)      ;; error: void-variable key
(ht-values table)    ;; error: void-variable value
(ht-items table)     ;; error: void-variable key

(ht-amap key table)                 ;; OK!!
(ht-amap value table)               ;; OK!!
(ht-amap (list key value) table)    ;; OK!!

I read your code, ht-keys and other two invoke macro ht-amap to do things, but the execution result of code above make me confused, I am not familiar with macro programming, but I am wondering if it is because something is missing from the original macro definition.

BTW, I am using Emacs 24.3.1

Regards,
Kelvin

ht-get as a macro or defsubst?

Hi again,

Just wondering, since ht-get just reorders the arguments to gethash, should it be defined as a macro or defsubst to avoid adding an extra function call? I don't know if it really matters, but e.g. I'm using it in my pocket-reader package, and it runs multiple times for every item in the list, so the overhead does add up (though I haven't profiled it, so I don't know if it's a problem for typical cases). But since there doesn't seem to be any downside...?

Thanks.

#'ht-get* behaves unexpectedly

ELISP> (ht-get* (ht-create) "a")
#<hash-table equal 0/65 0x3f63581>
ELISP> (apply #'ht-get* (list (ht-create) "a"))
#<hash-table equal 0/65 0x64af0dd>

I notice this on only the latest master branch. cc @Alexander-Miller

Reason for ht-set! returning nil?

puthash returns the value of the set key, just wondering if it would be better for ht-set!'s behavior to be consistent with this.

define-inline vs defsubst

The former is a more recent improvement over the latter, offering, among other things, better performance. The downside is that you'd require at least Emacs 25.
I've a PR at the ready if you think this is a worthwhile change.

Here's a comparison benchmark:

(define-inline ht-set-inline! (table key value)
  (inline-quote
   (prog1 nil
     (puthash ,key ,value ,table))))

(define-inline ht-get-inline (table key &optional default)
  (inline-quote
   (gethash ,key ,table ,default)))

(benchmark-run-compiled 10000
  (let ((ht (ht)))
    (dotimes (n 1000)
      (ht-set! ht n n))
    (dotimes (n 1000)
      (ht-get ht n))))

(benchmark-run-compiled 10000
  (let ((ht (ht)))
    (dotimes (n 1000)
      (ht-set-inline! ht n n))
    (dotimes (n 1000)
      (ht-get-inline ht n))))

On my system I get a result of 3.45s vs 3.16s, so we're looking at a ~9% improvement. Not the most impressive number, but over in treemacs ht is used in all the important places, so IMO every little bit helps.

Nested ht accessor macro?

Hi there,

Thanks for ht, it's very nice to use! I'm thinking about using it in pocket-reader, and so far it's working great in my tests. I store one global ht with each entry as a ht within it.

Accessing the hts within the global ht is easy enough, but I was wondering if you would consider adding a macro to ease access to nested hts, similar to how a and kv do it. Maybe something like:

(defmacro ht-nested (&rest keys)
  (cl-labels ((rec (keys)
                   `(ht-get ,(if (and (consp (cdr keys))
                                      (cddr keys))
                                 (rec (cdr keys))
                               (cadr keys))
                            ,(car keys))))
    (rec (nreverse keys))))

Used like:

(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-nested alphabets "Greek" 1 'letter))  ; => "α"

Thanks.

"context" macro

Hi,

Thanks for this library, I've enjoyed using it for a year or so now. Sometimes it can get a little verbose to make a bunch of ht-get calls or arrange your let or what have you. Using dash.el and s.el, I came up with a macro for single level key resolution. -- here's what I mean by that:

(setq example (ht (:foo "bar")))

(macroexpand-1
  '(ht-with-context
     example
     (concat "nice! " :foo)))

;; => (concat "nice! " (ht-get example :foo))

(ht-with-context
     example
     (concat "nice! " :foo))

;; => "nice! bar"

and the macro itself:

(defmacro ht-with-context (table content)
  (-tree-map
    (lambda (tree)
      (-tree-map-nodes (lambda (node) t)
        (lambda (node)
          (if (s-starts-with-p ":" (prin1-to-string node))
            (list 'ht-get table node)
            node))
        tree))
    content))

Anyway, just wanted to share -- thanks for the library!~

edit: I'll mention some caveats:

  • don't use this if your keys are changing often
  • the above doesn't check for the presence of they :key in your ht, so will mess up with other :keys in the form you pass it

Compiler warning

When byte-compiling ht.el I get the warning

cask exec emacs -Q -batch -f batch-byte-compile ht.el

In ht-set!:
ht.el:98:11:Warning: defsubst ‘ht-set!’ was used before it was defined

Probably ht-set! should just be moved more around to get rid of the warning.

Package cl is deprecated

(file-dependents (feature-file 'cl)) reports this component as depending upon cl which is deprecated
in favor of cl-lib in emacs 27 and higher. If I understand this correctly, the lib "cl" should be replaced with "cl-lib"

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.