all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Jean Louis <bugs@gnu.support>
To: tomas@tuxteam.de
Cc: Joel Reicher <joel.reicher@gmail.com>,
	Help GNU Emacs <help-gnu-emacs@gnu.org>
Subject: Re: Which Elisp data structure is fastest for searching?
Date: Thu, 26 Dec 2024 14:49:24 +0300	[thread overview]
Message-ID: <Z21CxHwI6RguV9bb@lco2> (raw)
In-Reply-To: <Z20gnOmHQv08x0FB@tuxteam.de>

[-- Attachment #1: Type: text/plain, Size: 3916 bytes --]

* tomas@tuxteam.de <tomas@tuxteam.de> [2024-12-26 12:25]:
> On Thu, Dec 26, 2024 at 11:53:38AM +0300, Jean Louis wrote:
> 
> [Hashes vs. ...]
> 
> > > This is why different data structures exist. There is no "best"; only "best
> > > for..."
> > 
> > As is written in manual that hash table is very fast, I believe yes,
> > though my search may not be.
> 
> Never believe such a thing out-of-context.

Sure, that is why I am asking possibly those who made better
experience with it.

(measure-time (seq-filter (lambda (item) (when (string-match "MY QUERY" (cdr item)) item)) my-alist)) ➜ "0.004352"

(measure-time (seq-filter (lambda (item) (when (string-match "MY QUERY" item) item)) my-list)) ➜ "0.004252"

(measure-time (delq nil (mapcar (lambda (key) (when (string-match "MY QUERY" (gethash key my-hash)) key)) (hash-table-keys my-hash)))) ➜ "0.004506"

I have measured list, alist, hash, with bit different functions, for
my 1300 page information pieces, I will keep measuring. Though small
inconceivable differences matter not.

I think hash method is so much easier, I can keep it all in the single
hash, and only query those keys which are relevant:

Following I would not query:

    (puthash (intern (format "id-%d-name" id)) name wrs-search-hash)
    (puthash (intern (format "id-%d-link" id)) link wrs-search-hash)
    (puthash (intern (format "id-%d-description" id)) description wrs-search-hash)
    (puthash (intern (format "id-%d-keywords" id)) keywords wrs-search-hash)))

I would query only those which are numeric, for example. Then I would
use `id-123-name' to get the name for numeric key 123.

> As others have already pointed out, it depends *a lot* on how you are
> searching. If your search always involves *exact* matches, hash tables
> might be what you need.

I will need to use AND, OR, NOT and there will be little different
functions to search within the has depending of the combinations
allowed.

> If these are more complex matches (think, as
> a working example: case-insensitive match), "naked" hashes are pretty
> useless, since your code might well end up walking all of the entries
> to apply the "custom comparison function" anyway.

I will only use values to search name, url, description, summary

> Sometimes (again, think our "case-insensitive match" example, a hash
> still might be useful: you may map the keys appropriately before
> hashing (again, in our example: lower case) and search for the equally
> mapped search item. Sometimes this reduces precision and you may get
> "false positives" -- but then you can refine your sequential search
> over a much reduced set (this is, BTW, the same thing hash tables do,
> but I disgress).

Okay, thanks. 

> Another context point is size. For small things, hashes haven't an
> advantage over alists.

I think 1300 x 4 elements is small thing.

> Here's a small code snippet. On my machine, and in the current
> moon phase, hashes overtake alists at roughly 10 entries:
> 
 (let* ((size 10) ; alist, hash size
        (runs 100000) ; benchmark runs
        (alist '())
        (hash (make-hash-table :test 'eq :size 1549))
        (keys (make-vector size nil))
        (count size))
   ;; setup
   (while (> count 0)
     (setq count (1- count))
     (let ((sym (intern (format "SYM%04d%03d" (random 10000) count))))
       (aset keys count sym)
       (setq alist (cons (cons sym "foo") alist))
       (puthash sym "foo" hash)))
   ;; run
   (cons
    (benchmark runs '(assq (aref keys (random size)) alist))
    (benchmark runs '(gethash (aref keys (random size)) hash)))) 

➜ ("Elapsed time: 0.030115s" . "Elapsed time: 0.028604s")

I see no much difference, important is there is no human noticeable 😐
too long ⏱️ lag, small ⚖️ lags are always there 👍.

Okay thanks, I am advancing.

-- 
Jean Louis

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

  reply	other threads:[~2024-12-26 11:49 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-12-25  9:33 Which Elisp data structure is fastest for searching? Jean Louis
2024-12-26  6:24 ` Joel Reicher
2024-12-26  8:53   ` Jean Louis
2024-12-26  9:23     ` tomas
2024-12-26 11:49       ` Jean Louis [this message]
2024-12-26 23:03     ` Joel Reicher
2024-12-27 11:16       ` Jean Louis
2024-12-28  3:32         ` Joel Reicher

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Z21CxHwI6RguV9bb@lco2 \
    --to=bugs@gnu.support \
    --cc=help-gnu-emacs@gnu.org \
    --cc=joel.reicher@gmail.com \
    --cc=tomas@tuxteam.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.