How to lappend to nested dicts?

Showing 1-6 of 6 messages
How to lappend to nested dicts? Georgios Petasis 7/19/12 11:07 AM
Hi all,

I was looking the dict manual, and I realised that it is very easy to
create nested directories (with dict set), but is not so easy to lappend
values to nested dictionaries.

For example:

dict set d person name phone_numbers 1

returns a dict with nested dictionaries:

person {name {phone_numbers 1}}

But what is the most efficient way to append a new phone number to the
last dict?

Initially I thought that the following would work:

dict lappend d person name phone_numbers 2

But it does not. What is the best alternative?

(From the manual I am not sure that I understood what dict update & dict
with are supposed to do. I am totally lost with the examples.)

George
Re: How to lappend to nested dicts? Georgios Petasis 7/19/12 11:17 AM
Is the following the most efficient way to lappend items to a nested dict?

set d [dict create]

set id 0
foreach name {petasis petasis petasis} {
   if {[dict exists $d person $name]} {
     dict with d person {
       lappend $name [incr id]
     }
   } else {
     dict set d person $name [list [incr id]]
   }
}
puts $d

Because I need to do this for about 500.000 items...

George
Re: How to lappend to nested dicts? Harald Oehlmann 7/20/12 12:30 AM
Hi Heorge,

I have tried it, but my knowledge is not sufficient, sorry.
Here are the traces:
http://wiki.tcl.tk/19938
Feel free to edit.
-Harald
Re: How to lappend to nested dicts? Ben Collver 7/20/12 7:00 AM
On Thursday, July 19, 2012 11:07:16 AM UTC-7, Georgios Petasis wrote:
> Hi all,
>
> I was looking the dict manual, and I realised that it is very easy to
> create nested directories (with dict set), but is not so easy to lappend
> values to nested dictionaries.
>
> For example:
>
> dict set d person name phone_numbers 1
>
> returns a dict with nested dictionaries:
>
> person {name {phone_numbers 1}}
>
> But what is the most efficient way to append a new phone number to the
> last dict?
>
> Initially I thought that the following would work:
>
> dict lappend d person name phone_numbers 2
>
> But it does not. What is the best alternative?
>
> (From the manual I am not sure that I understood what dict update & dict
> with are supposed to do. I am totally lost with the examples.)
>
> George


proc dict_klappened {dictVar args} {
    if {[llength $args] < 2} {
        error "wrong # args: should be \"klappened dictVar key ?key ...? value\""
    }
    upvar $dictVar that
    if {[llength $args] == 2} {
        set key [lindex $args end-1]
        set value [lindex $args end]
        dict lappend that $key $value
    } else {
        set key [lindex $args 0]
        set argz [lrange $args 1 end]
        dict with that {
            dict_klappened $key {*}$argz
        }
    }
}

dict set d person name phone_numbers 1
dict_klappened d person name phone_numbers 2
unk...@googlegroups.com 7/24/12 10:48 AM <This message has been deleted.>
Re: How to lappend to nested dicts? Emiliano 7/24/12 10:56 AM
On Thursday, July 19, 2012 3:07:16 PM UTC-3, Georgios Petasis wrote:
> Hi all,
>
> I was looking the dict manual, and I realised that it is very easy to
> create nested directories (with dict set), but is not so easy to lappend
> values to nested dictionaries.
>
> For example:
>
> dict set d person name phone_numbers 1
>
> returns a dict with nested dictionaries:
>
> person {name {phone_numbers 1}}
>
> But what is the most efficient way to append a new phone number to the
> last dict?
>
> Initially I thought that the following would work:
>
> dict lappend d person name phone_numbers 2
>
> But it does not. What is the best alternative?
>
> (From the manual I am not sure that I understood what dict update &amp; dict
> with are supposed to do. I am totally lost with the examples.)


Since [dict] is an ensemble command, you can easily add your own
subcommand to [lappend] to nested dictionaries.
The following version uses [dict with]:

proc ::tcl::dict::lappend2 {dict args} {
     upvar 1 $dict d
     with d {*}[lrange $args 0 end-2] {
          ::lappend [lindex $args end-1] [lindex $args end]
     }
}
namespace ensemble configure dict -map \
    [dict merge [namespace ensemble configure dict -map] \
        {lappend2 ::tcl::dict::lappend2}]


testing:

% dict set d person name phone_numbers 1
person {name {phone_numbers 1}}
% dict lappend2 d person name phone_numbers 2
1 2
% set d
person {name {phone_numbers {1 2}}}

Regards
Emiliano