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.
RS: Note that in recent versions lsearch has gained many additional options and almost turned into a powerful "search engine":
So the following call has grep-like functionality, if you search a list of lines:
lsearch -regexp -inline -all $lines $regexp
A cute little wrapper for the most frequent use case (for me at least) is:
proc in {list element} {expr [lsearch -exact $list $element] >= 0}
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. (Matthias Hoffmann: But wouldn't it be better to implement a -nocase-operator for those cases to avoid using the 'battleship' regexp for such simple daily cases...????)
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 TIP 127 [L1 ] -index option.
JMN 2005-12-11 Along with new commands like lrepeat.. this makes Tcl pretty neat for manipulating matrices (nested lists). e.g
set m [lrepeat 3 [lrepeat 3 0] % {0 0 0} {0 0 0} {0 0 0} lset $m 1 0 1 ; lset $m 2 0 2 % {0 0 0} {1 0 0} {2 0 0}
Now you can retrieve in columnwise fashion like this:
lsearch -all -inline -subindices -index 0 $m * %0 1 2
But it seems a bit funny to be using lsearch in 'glob' mode when we are really wanting to do positional access. Without resorting to extensions.. is there a better way?
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