lappend appends
elements to a list.
Synopsis edit
-
- lappend varName ?value value ...?
Description edit
lappend creates a variable named
varname if it does not exist, appends each
value to the list stored in
varName, and returns the value of
varName.
lappend differs from
append in that values are appended as elements in the list rather than raw text.
lappend operates on the specified list in-place, so it is not necessary to assign the results of
lappend to
varName. This is why the first argument to
lappend is the name of a variable rather than the list value itself.
It is an error if the value of the variable named
varName is not a list.
% set x \{ ;# string that is not a list
{
% lappend x b ;# treat it as list
unmatched open brace in list
Examples:
lappend auto_path /usr/local/lib/tcl8.5
#Does nothing but fail if listName is not a well-formed list.
lappend listName
Incorrect usage:
#warning: bad code ahead
set auto_path [lappend $auto_path /usr/local/lib/tcl8.5]
lappend $listName
the problem in the set example is not the use of lappend in the [ ... ] construct, but the use of
$auto_path as the first argument instead of
auto_path (without the
$).
List Validation edit
Another function of
lappend is to validate a value as a well-formed list. When invoked with no
values,
lappend simply makes sure that the value of the variable named by
varName is a valid list, and returns it:
RS 2006-10-01:
jcw contributed this (for me) surprising
idiom:
lappend var
does nothing, but creates
var if it doesn't exist. Similar to, but simpler than:
if {![info exists var]} {set var ""}
This may however fail if
$var holds a string that cannot be parsed as a list.
wdb: It works, but it is some kind of
dirty trick as it is based on some Tcl-internal optimizing located far out of documented behaviour. The greater danger is
not to throw an error. Exemplum gratia, here
lappend works as you describe:
% set a "a {b} c"
a {b} c
% lappend a
a {b} c
but here not:
% set a "a {b} c"
a {b} c
% lappend a x
a b c x
Unintended side effect: word b has "forgotten" its surrounding braces as they are not necessary for identifying b as a word .
I don't think that this will fit to the category
quick'n'dirty as it is perhaps dirty enough but not quick if you are hunting the resulting bugs on friday afternoon ;-)
Lars H: Well, if you care about the braces, then apparently you don't merely see the value as a list, and in that case using
lappend probably isn't the right thing to do (as
it will only respect the list interpretation of the value).
jcw has also been seen using
append in the same way, when the value is a more general string.
Unique [lappend] edit
jmn 2008-06-04:
I find myself using code like the following very often:
if {$element ni $list} {
lappend list $element
}
I know it's not much code.. but It seems to me it'd be neat to have an option so you could instead do something like:
lappend -ifmissing list $element
jcw: This indicates you're using a list as a set. You could also consider using 8.5's
dict set list $element {} for a slightly different approach.
AMG: Faster, too, though it honks up the string representation to have every other word be empty string. Use [
dict keys] to get your data back without the empties.
If you don't have [
dict], use [
set list($word) {}] instead, then [
array names] will give you the list of word. Though you're using
ni, so I'm sure you will have [dict]...
RS 2008-06-04: I just add a convenience proc whenever I need that functionality:
proc ladd {_list el} {
upvar 1 $_list list
if {$el ni $list} {lappend list $el}
}
List concatenation edit
AMG: [lappend] can be used with the
{*} expansion operator to concatenate lists.
lappend listVariable {*}$otherListVariable
lappend listVariable {*}[scriptReturningList]
But what if you don't have
{*}? Then you can use [
eval] or [
concat]. Here's a demonstration of the latter:
set listVariable [concat $listVariable $otherListVariable]
set listVariable [concat $listVariable [scriptReturningList]]
There is one subtlety being missed. [lappend] is a
creative writer, meaning that it creates the named variable if it doesn't already exist. The above code will not do this since it starts by taking its value to get the first argument to [concat]. Solution? Use [
append] to append empty string to the variable, which creates it if it's not there but otherwise leaves it unchanged. What's more, [append] returns the variable's value, so it all fits in a one-liner,
functional context:
set listVariable [concat [append listVariable {}] $otherListVariable]
set listVariable [concat [append listVariable {}] [scriptReturningList]]
See also edit
- list