A nifty definition for dictionaries / hashes

Started by Lutz, September 07, 2006, 06:37:34 AM

Previous topic - Next topic

Lutz

Just discovered this nifty little definition to make dictionary/hash handling more comfortable with less typing:


(define (myhash:myhash key value)
   (if value
       (context 'myhash key value)
       (context 'myhash key)))
       
(myhash "hello" 123)

(myhash "hello")    => 123


Lutz



ps: also added to the manual

arunbear

#1
Here it is as a module:



(context 'Dict)

(define (Dict:Dict key value)
   (if value
       (context (context) key value)
       (context (context) key)))

(define (get key) (Dict key))
(define (put key value) (Dict key value))

(define (keys)
    (map name (difference
                (symbols)
                (cons
                    (sym (string (context)) (context))
                    '(Dict get put keys key value values)))))

(define (values)
    (map get (keys)))

(context MAIN)

Usage:

> (new Dict 'd)
d
> (d "name" "fred")
"fred"
> (d "age" 10)
10
> (d:put "salary" 10000)
10000
> (d:get "salary")
10000
> (d:keys)
("age" "name" "salary")
> (d:values)
(10 "fred" 10000)

arunbear

#2
Hi Lutz, in Perl you can iterate through the (key, value) pairs of a dictionary without loading the whole keyset into memory



e.g.
my %dict = (name=> 'Aragorn' , alias=> 'Strider');
while(($key, $val) = each %dict)
{
    print "key = $key, value = $valn";
}


Python and Ruby have similar constructs.



How can this be done in newlisp? dotree would visit all symbols in the underlying context, even those that are not keys of the dictionary.

Lutz

#3
It is better to use just one function (and not inside a module) to define a Dictionary:



(define (words:words key value)
   (if value
       (context 'words key value)
       (context 'words key)))

> (words "one" 1)
1
> (words "two" 2)
2
> (words "three" 3)
3
> (words "four" 4)
4
>


now there is only one symbol to exclude containing the function definition:


(dotree (w words)
    (if (not (lambda? (eval w)))
        (println (name w) "=>" (eval w))))

; will output

four=>4
one=>1
three=>3
two=>2


I think in practice the best is always to define dictionaries explicitely using 'context'


(context 'words "one" 1)
(context 'words "two" 2)
(context 'words "three" 3)


and then 'dotree' does not need exclude any symbols:


(dotree (w words)
        (println (name w) "=>" (eval w))))

; will output

four=>4
one=>1
three=>3
two=>2






Lutz

cormullion

#4
Is this the sort of thing that people can do with macros? I don't know enough about macros yet, but perhaps it could provide you with the more selective route through a context's symbols:



This sort of thing (warning: macro-newbie at work :-)):


(define-macro (do-keys)
(letex (v (first (first (args))))
(dotree (v (last (first (args))))
(if (not (lambda? (eval v)))
(map eval (rest (args)))))))


which might then render arunbear's Dict example module like this:


(do-keys (s d)
(println s " " (eval s)))

d:age 10
d:key nil
d:name fred
d:salary 10000
d:value nil


compared with this:


(dotree (s d)
(println s " " (eval s)))

d:Dict (lambda (d:key d:value)
 (if d:value
  (context (context) d:key d:value)
  (context (context) d:key)))
d:age 10
d:d (lambda (d:key d:value)
 (if d:value
  (context (context) d:key d:value)
...


But as I said, I'm still trying to understand this stuff...