Version 17 of lsearch

Updated 2004-08-20 19:25:49 by lwv

http://www.purl.org/tcl/home/man/tcl8.4/TclCmd/lsearch.htm

The simplest invocation form for lsearch is:

 lsearch list search_term

lsearch searches the first argument list for an element that matches the search_term argument.

caspian: lsearch returns -1 if search_term was not found.


Suppose you have this list:

    set yourlist {RedHat SUSE Debian Knoppix Peanut Mandrake Slackware}

...and you run lsearch to check if a given Linux distribution is present in the list. If it is, it will return the index, i.e. its position in the list.

    lsearch $yourlist RedHat

...would return 0 (zero) because the count starts from zero and "RedHat" is the first item in the list. "SUSE" would return 1 (one) and "Slackware" would return 6 (six).

If the item is not present in the list, the search returns -1 (minus one), so in order to check the presence of an item in the list, we can just check if the return value is a positive number, i.e. greater than zero or zero:

    if  { [ lsearch $yourlist Debian ] >= 0 }   {
         puts "Debian is in the list"
    }  else  { puts "There is no Debian in the list" }

"RedHat" can be a tricky string to search because it is mixed case, so scroll down this page to see how we can run a case-insensitive search within a list. It involves using regular expressions in the search string.

If you get to use regular expressions, -inline becomes a very useful switch. It makes lsearch return the element found instead of its index. Or, instead of regular expressions, we can use a simple glob pattern. Run...

    lsearch -inline $yourlist *ware

... and get Slackware instead of a relatively meaningless integer, i.e. the list index.

But note that all searches above will return the first element found. If you want to find all matches, use the -all switch:

    lsearch -all $yourlist *an*

...returns the list {2 4 5}: Debian, Peanut and Mandrake.

Combine -all with -inline and get all names instead of all indices:

    lsearch -all -inline $yourlist *an*

... returns the list {Debian Peanut Mandrake}


The default for lsearch is -glob . However, be certain the glob behavior is what you expect.

For instance, check out this code.

 set a [list field1:val1=field3 field2:val2=2 field3:val3=3 field3]
 set b [lsearch $a field3]
 puts $b

Would you expect glob to mean that element 0, 2, or 3 would be returned? 3 is the answer you get. On the other hand,

 set b [lsearch -regexp $a field3]
 puts $b

returns 0.


Case-insensitive lsearch: Use (?i) in the -regexp for case-insensitive comparison:

 % lsearch -regexp {Foo Bar Grill} {(?i)BAR}
 1

From Tcl 8.4, fancy new modes have been added: -all gives you all instances (instead of the first only); -inline gives the elements themselves instead of their index. So a very easy filter that removes empty sublists from a list is

 lsearch -all -inline $list ?* ;# RS - example:

 % lsearch -all -inline {foo {} bar {} grill} ?*
 foo bar grill

From 8.5 on there will be even more switches, for example TIP127 -index option.


See also list, lappend, lindex, linsert, llength, lrange, lreplace, lsort . Recursive list searching gives you an index vector which can be used with lindex/lset.


Tcl syntax help - Arts and crafts of Tcl-Tk programming - Category Command