Ralf
Ralf

Reputation: 1295

Tcl: test for nested list

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

Answers (2)

Colin Macleod
Colin Macleod

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

Colin Macleod
Colin Macleod

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

Related Questions