5

I have a hash-table (named ztree-line-to-node-table) that stores the line-number and the corresponding absolute-file-name. The absolute-file-name is extracted using (gethash line ztree-line-to-node-table).

Q:   How, please, can I extract the line-number if I know what the absolute-file-name is?

#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data
      (1
       #("/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app" 0 49
     (face ztree-start-node-face))
       2 "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents" 3 "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents/MacOS" 4 "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents/Resources" 5 "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents/Info.plist" 6 "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents/PkgInfo"))

EXAMPLE:

  • The absolute-file-name is a path:

"/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents"

  • The line-number is 2.

I am looking for a means of programmatically querying the hash-table using the absolute-file-name to extract the line-number -- the result of the query in this example is 2.

lawlist
  • 18,826
  • 5
  • 37
  • 118

3 Answers3

6

If you need bidirectional mapping, you are probably using the wrong data structures — hashtables provide fast mapping in one direction, but mapping in the reverse direction requires iterating over the whole hashtable (as in lawlist's answer).

You don't say how many entries you expect there to be in the table. If it's just a few hundred, then you could probably get away with an association list, and use the functions assoc and rassoc to perform the direct and reverse mapping.

If you have many entries, the simplest solution is to use two hashtables, one that maps line numbers to filenames, and one that maps filenames to line numbers. Of course, you will need to make sure that the two tables are kept in sync — that you always insert and delete an entry from both hashtables; if you don't, you'll end up with confusing bugs that will be difficult to identify.

jch
  • 5,680
  • 22
  • 39
  • I like your idea for two hash-tables (one in each direction), so that I can design the major-mode to support a large amount of folders / files in an efficient manner. Essentially, I have a tree-view of the hard drive(s) -- which can be set with the top node being as deep into the directory tree as desired. Getting back to the right line number is being used for re-marking (previously marked) folders/files after the buffer regenerates, and for moving point back to the previous node after the buffer has regenerated and the line number is different because something has been added or removed. – lawlist Nov 10 '14 at 00:01
  • Okay, I've implemented your suggestion -- the only tricky part was learning that the default test is `eql`, and when using an absolute file-name, it is necessary to use `(make-hash-table :test 'equal)` so that `gethash` works correctly using the file-name as the `key`. Thank you very much! – lawlist Nov 10 '14 at 03:04
2
(defun ztree-get-line-number (absolute-filename)
  (catch 'done
    (maphash
      (lambda (line filename)
        (when (equal filename absolute-filename)
          (throw 'done line)))
      ztree-line-to-node-table)))

The above-function is a modification of the example in the Elisp Cookbook:

http://www.emacswiki.org/emacs/ElispCookbook#toc44

(let ((nick-table (make-hash-table :test 'equal))
      nicks)
  (puthash "kensanata" "Alex Schroeder" nick-table)
  (puthash "e1f" "Luis Fernandes" nick-table)
  (puthash "pjb" "Pascal J. Bourguignon" nick-table)
  (maphash (lambda (nick real-name)
             (setq nicks (cons nick nicks)))
           nick-table)
  nicks)
  ==> ("pjb" "e1f" "kensanata")
lawlist
  • 18,826
  • 5
  • 37
  • 118
1

Instead of an hashtable ztree-line-to-node-table I suggest creating a bidirectional hashtable ztree-line<->node-table, whose key and values type would both be strings, and whose key value pairs would be duplicated in both directions.

For instance:

> (gethash "2" ztree-line<->node-table)
  "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents"

> (gethash "/Users/HOME/.0.data/.0.emacs/Emacs_10_01_2014.app/Contents" ztree-line<->node-table)
  "2"
Paulo Tomé
  • 111
  • 5
  • This obviously depends greatly on the nature of the data, as it would immediately break down if you ever had a clash between a key and a value. As this approach would still need to be managed manually, I think two hash tables seems the safer option in general. – phils Nov 10 '14 at 04:41