简体   繁体   中英

Most efficient way to search a tcl list

i have a tcl list as below.

set mylist [list a b c d e]; # could be more

Now i am doing some processing if the list contains the items "c", "d", "e". But i need to skip that processing if and only if the list has either of the below values:

set mylist [list a];

OR

set mylist [list b];

OR

set mylist [list a b];

So if mylist is any of the above three, i skip the processing. But lets say if the list has any values other than the above three combinations, i do the processing.

What is the most efficient way of searching if the list has any of the three combinations.

I have the basic code which is fulfilling my requirement, but i was looking for more efficient way as i am not much familiar with tcl containers.

set mylist [list a];

if {[llength $mylist] == 2 && ([lindex $mylist 0] eq "a" || [lindex $mylist 0] eq "b") && ([lindex $mylist 1] eq "a" || [lindex $mylist 1] eq "b")} {
  puts "1. skip the processing"
} elseif {[llength $mylist] == 1 && ([lindex $mylist 0] eq "a" || [lindex $mylist 0] eq "b")} {
  puts "2. skip the processing"
} else { 
  puts "Do the processing" 
}

I was wondering if there is any other efficient way to perform the same.

if {$mylist in {a b {a b}}} {
    puts "skip the processing"
}

A list isn't a string, but we can usually compare lists to strings for equality and order. A list with a single element "a" is comparable to the string "a". If you want to know if a given string is equal to any of the lists in the question, the easiest way is to check if the value of the list is a member of the list {ab {ab}} .

Note: This particular solution does not solve all aspects of list equality in general. It works in those cases where it works.

Efficiency

Is it really efficient to compare a list to a string when this will cause automatic, repeated reconstruction of the internal representation of the data ("shimmering"). Actually, it is. If one compares the procedures

proc foo1 mylist {
    set a 0
    if {$mylist in {a b {a b}}} {set a 92}
    return $a
}

proc foo2 mylist {
    set a 0
    if {$mylist in [list [list a] [list b] [list a b]]} {set a 92}
    return $a
}

then foo1 seems to be faster than foo2 (different machines may produce different results).

Constructing a list inside the condition evaluation code does not seem to add very much time. This procedure

proc foo3 mylist {
    set a 0
    set x [list [list a] [list b] [list a b]]
    if {$mylist in $x} {set a 92}
    return $a
}

is somewhere in between foo1 and foo2 in speed, but not significantly faster than foo2 .

One can also do this by invoking lsearch :

proc foo4 mylist {
    set a 0
    set x [list [list a] [list b] [list a b]]
    if {[lsearch $x $mylist] >= 0} {set a 92}
    return $a
}

proc foo5 mylist {
    set a 0
    set x [list [list a] [list b] [list a b]]
    set i [lsearch $x $mylist]
    if {$i >= 0} {set a 92}
    return $a
}

which is comparable to foo2 and foo3 .

(In case it needs to be said, lsearch is more versatile than the in operator, offering eg case insensitive lookup, regex lookup, etc. If you need such things, lsearch is the best option.)

I've deleted most of my observations and theories on speed after timing the procedures on another machine, which showed quite different results. foo1 was consistently faster on both machines, though. Since that code is simpler than the other alternatives, I would say this is the way to do it. But to be sure, one needs to time the procedure with one's own machine, whitelist, and code to be performed.

Finally, none of this really matters if I/O occurs inside the procedures, since the I/O will be so much slower than anything else.

Documentation: if , list , lsearch , proc , puts , return , set

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM