Reputation: 1295
How can I efficiently test whether a Tcl list is nested (i.e. contains lists as elements)?
Based on https://wiki.tcl-lang.org/page/Depth+of+a+list I constructed the following proc:
proc isNestedList {l} {
return [expr ![string equal $l [concat {*}$l]]]
}
This gives the desired behavior (except for the case {A}
which generally cannot be handled differently as far as I know, see https://stackoverflow.com/a/66799916/3852630):
% isNestedList A
0
% isNestedList {A}
0
% isNestedList {{A}}
1
% isNestedList {A B}
0
% isNestedList {{A B}}
1
% isNestedList {A {B C}}
1
However, for long lists which are not nested, isNestedList
is slow, probably due to the conversion from list to string. I tried a different version where I compare $l
and [concat {*}$l]
by ::struct::list equal
(https://tools.ietf.org/doc/tcllib/html/struct_list.html) to avoid this conversion, but that is even slower.
Thanks a lot for your help!
Upvotes: 1
Views: 289
Reputation: 4372
I realised that my earlier answer is overcomplicated and less than optimal. I think this is better:
proc isNestedList l {
foreach a $l {
if {$a ne [lindex $a 0]} {
return true
}
}
return false
}
Upvotes: 1
Reputation: 4372
To avoid the slowdown you mention, you need to stick to list operations, not string operations. Here's one way:
proc isNestedList l {
return [llength [lmap a $l {expr {[llength $a] > 1 ? 1 : [continue]}}]]
}
This uses lmap
to filter the list down to only those elements which can themselves be treated as a list of more than one element, then checks if the resulting list is non-empty.
Upvotes: 1