Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

"recursive" [dict filter]?

358 views
Skip to first unread message

David Rysdam

unread,
Jul 13, 2016, 10:49:13 AM7/13/16
to
[dict filter] doesn't behave like I want on a nested dict and I'm
wondering what the idiom is supposed to be here.

set d [dict create]
dict set d node leafL L
dict set d node leafR R

I would expect some simple way to retrieve the "dict tree" that leads to
exactly whatever key and/or values I specify. But I can't figure out how
to, for instance, only get paths to the left leaves. Here's the most
obvious thing:

puts [dict filter $d value L]

that returns blank. This:

puts [dict filter $d value "*L*"]

returns the entire tree. Using script:

puts [dict filter $d script {k v} {
if {$v == "L"} {
return true
}
return false
}]

is also blank.

It behaves as though it only operates at the "top level" and isn't
recursing to inner dicts. Given that other dict operations understand
nested dicts, I must just be missing some obvious method...?

Peter Lewerin

unread,
Jul 13, 2016, 11:31:27 AM7/13/16
to
Den onsdag 13 juli 2016 kl. 16:49:13 UTC+2 skrev David Rysdam:

> puts [dict filter $d script {k v} {

> It behaves as though it only operates at the "top level" and isn't
> recursing to inner dicts. Given that other dict operations understand
> nested dicts, I must just be missing some obvious method...?

Yes, dict filter only operates on the immediate items in the dictionary value, the "top level" if you will. However, the value in v is the dictionary value on the next recursive level for each of the items, so you can implement a recursive search yourself. Offhand, I'd probably use dict for instead to do this.

Note that you can't use return to set the value of the script: it will terminate the dict filter / dict for command instead.

David Rysdam

unread,
Jul 13, 2016, 11:57:00 AM7/13/16
to
I don't know what you mean by return terminating the filter/for. [dict
for] also seems to only operates on the "immediate items".

dict for {k v} $d {
puts "key: $k"
}

outputs only

key: node

I guess you could make an helper proc (possibly anonymously) that did
the recursion. Is there a snippet somewhere that does this in general?

Peter Lewerin

unread,
Jul 13, 2016, 12:07:57 PM7/13/16
to
Den onsdag 13 juli 2016 kl. 17:57:00 UTC+2 skrev David Rysdam:

> I don't know what you mean by return terminating the filter/for.

The return command in the script causes the dict filter command to end when evaluating the script the first time, without iterating through the rest of the items.

> [dict for] also seems to only operates on the "immediate items".

Yes, all the iterating dict commands do that, IIRC.

> I guess you could make an helper proc (possibly anonymously) that did
> the recursion. Is there a snippet somewhere that does this in general?

I'm not aware of any. If you could clarify, preferably with real data, what you want to achieve, I could possibly write up something to start with.

David Rysdam

unread,
Jul 13, 2016, 12:37:19 PM7/13/16
to
That's OK. I can do it--I just thought I'd save time by reusing code. I
must be using dicts differently than others, since it seems like
filtering a pile of data by one of the "sub"-properties would be a
common task.

Peter Lewerin

unread,
Jul 13, 2016, 1:12:28 PM7/13/16
to
Den onsdag 13 juli 2016 kl. 18:37:19 UTC+2 skrev David Rysdam:

> I must be using dicts differently than others, since it seems like
> filtering a pile of data by one of the "sub"-properties would be a
> common task.

Or I'm just misunderstanding you. It's possible that dicts haven't really settled yet in the patterns and recipes of the Tcl community. I get barely a thousand hits when I search for the string "dict filter" (with some common language names removed), so it doesn't really seem to be on the radar.

Andreas Leitgeb

unread,
Aug 4, 2016, 4:15:56 PM8/4/16
to
While skimming over that (weeks old) thread about dict filter, I played
around a bit: (dict filter somehow felt like new to me - had forgotten
that it even exists)

# preparation:
% set d [dict create a b]

# return within a dict filter script body:
% dict filter $d script {k v} { return 1 }
command returned bad code: 0
% catch { dict filter $d script {k v} { return 1 } } m o
2
% set o
-code 0 -level 1

# return at top level (ditto within foreach/if/while bodies)
% return 1
1
% catch { return 1 } m o
2
% set o
-code 0 -level 1

% return -code 2 1
command returned bad code: 2
% catch { return -code 2 1 } m o
2
% set o
-code 0 -level 2


Summary:

while >dict filter< with a "return" in the script appears to behave like
"return -code 2 1"
directly on the tcl command line, it appears to behave more like
"return 1"
when comparing the errordict captured through catch

It looks somewhat inconsistent to me.
Is it a "level off by 1" bug between compiled and interpreted code?
Some special case in the main loop processing my input and reporting
result?
Or just a pebkac?

PS: tclsh 8.6.5 here (Ubuntu 16.04)

Peter Lewerin

unread,
Aug 4, 2016, 5:28:12 PM8/4/16
to
Note that the script doesn't get its own scope to execute in: it executes in the same scope as the command was invoked in. I suppose that if you invoke the command in the global scope and the return command tries to return to the caller's level, something goes kaput.

If you invoke the same command from a procedure, there is no error (but the dict filter command is interrupted and the procedure returns immediately).

Peter Lewerin

unread,
Aug 4, 2016, 6:07:24 PM8/4/16
to
Den torsdag 4 augusti 2016 kl. 23:28:12 UTC+2 skrev Peter Lewerin:

Ok, that's not the whole story. if 1 {return 1} should behave the same way but doesn't.

Peter Lewerin

unread,
Aug 5, 2016, 7:41:16 AM8/5/16
to
Den torsdag 4 augusti 2016 kl. 22:15:56 UTC+2 skrev Andreas Leitgeb:

OK, reading TIP 90 to understand this better I notice that you are one of the contributors. I will now stop presuming to be able to lecture you on this :)
0 new messages