concat, a
built-in command, joins strings together. If the strings are lists, the effect is to join the lists together.
Synopsis edit
-
- concat ?arg arg ...?
Description edit
Trims the leading and trailing whitespace from the arguments and joins them together, adding a white space between them. If all the arguments are lists, this has the same effect as concatenating them into a single list, hence the name, "concat". When the arguments are not well-formed lists, the result may not be a well-formed list either, but there is no error raised. [
concat] permits any number of arguments. With no arguments, the result is an empty string.
Lars H: [
concat] is indeed defined as an operation on general strings (partly because it is used also by [
eval], which often operates on strings in a not-quite-list manner). However, when all arguments are
pure lists then it can take a shortcut that avoids working with the string representations.
For pure list concatenation, use
{*}:
# Instead of: set foo [concat $bar $boo $spong]
set foo [list {*}$bar {*}$boo {*}$spong]
Documentation edit
- official reference
See Also edit
- list
- append
Examples edit
concat a b {c d e} {f {g h}}
which produces the value
a b c d e f {g h}
[
concat] has no problem with strings that are not well-formed lists:
concat " a b {c " d " e} f"
;# -> a b {c d e} f
The result happens to be a valid list, but the inputs were not:
% string is list -strict " a b {c "
0
% string is list -strict d
1
% string is list -strict " e} f"
0
% string is list -strict [concat " a b {c " d " e} f"]
1
[
concat] also happily returns values which are not well-formed lists:
set l [concat \{ a b c]
lindex $l 0
;# -> unmatched open brace in list
AMG PYK: [
concat] is defined in terms of
string concatenation;
list concatenation is "merely" an optimization applied when all arguments are
pure lists. See
tclUtil.c. In the previous example, the first argument is not a valid list, let alone a pure list.
[string is list \{] returns
0. concat's remaining arguments aren't pure lists either, even though they're valid lists.
[
concat] does not modify its inputs in any way, except to insert a space between them. It does not, for example, remove spaces from the middle of its arguments:
concat "a b c" { d e f }
#; -> a b c d e f
In the result, there are still three spaces between
a,
b and
c.
To make sure the inputs are valid lists, use [
lappend] instead:
lappend mylist {*}$myotherlist
See
Concatenating lists for a timing comparison of various methods.
Other methods of putting strings together include:
set a abc
set b 127
set c $a$b
set c [format {%s %s} $a $b]
join [list $string1 $string2]
set list [concat {} a b]
llength $list ;# -> 2
set list [concat {{}} a b]
llength $list ;# -> 3
Performance edit
slebetman - If I'm not mistaken,
concat have been optimised in 8.4 to not shimmer when processing pure lists. In fact it is even faster than
linsert:
% set a [list a b c]
% time {set a [linsert $a 0 d]} 10000
41.1639 microseconds per iteration
% set a [list a b c]
% time {set a [concat d $a]} 10000
4.8214 microseconds per iteration
Lars H: As far as I can tell, this is not using the
pure list optimisations of
concat -- you're seeing the string performance of that command! If you try it with larger list elements, performance should start to favour
linsert instead. You might also want to check what happens if you rewrite the above using the
K combinator to let
linsert operate on an unshared
Tcl_Obj; this appears to be the case that
linsert is optimised for (even though it is probably rather rare, hmm...).
slebetman: Quite right, testing with large 100 character strings gives me 36.7218 microseconds per iteration for
linsert but a staggering 1609.4685 microseconds per iteration for
concat - yikes!
Lars H: Good advices when experimenting with these things are:
- Put all arguments you want to experiment with in variables, to avoid confusion like above of what is done by the parser and what is done by the command.
- Test the values you put in variables using llength, lindex, etc. to see that it really is what you want it to be.
Concatenating Elements of Sublists edit
In Tcl 8.5, the proper way will be to use
{*}:
concat {*}$matrix
In Tcl 8.4 we made do with
eval [list concat] [lrange $matrix 0 end]
or
eval [linsert $matrix 0 concat]
In most reasonable cases,
eval [list concat] $matrix
will work as well, but it will give unpleasant surprises if there is a newline character between two elements of the $matrix.
Concatenating the sublists of a list (e.g. a matrix) is best done with
join.
Lars H PYK:
That is a rather controversial statement. An obvious problem with using
join is that it operates on the string representations of the sublists and thus loses any internal representations that may exist. If
tcl_precision is less than its maximum, then this will even result in loss of precision for numerical data when the number is converted to a less precise string! Also, I would like to see proof that using join can never result in the creation of malformed lists before trusting
join to do this.
Numerical Precision edit
[DBaylor
]: I find the behavior of concat bizarre. Numerical precision is lost with concat also - sometimes. At least with join you know you're losing precision. Here's an example:
set a [expr {1.0 / 3.0}]
set list_aa [concat [list $a] [list $a]]
# prints 1.0
puts [expr {3.0 * [lindex $list_aa 0]}]
set list_a0 [concat [list $a] [list]]
# prints 0.9999...
puts [expr {3.0 * [lindex $list_a0 0]}]
Lars H: It seems you have found a counterexample to the rule that "The result of
list is a
pure list." -- namely that the empty list returned by
list is just the empty string. I'd say this is a bug. Do you wish to report it, or should I? (That it matters at all is of course also a bug, but that one is deep and harder to fix.
KBK has a
TIP for 8.5 which will address it.)
AMG: Which
TIP?
Lars H:
TIP #132. It fixes the issue that conversion to string may cause loss of precision.
AMG: Oh, I misunderstood. I thought that
TIP would be to make [
list] return a
pure list, not an empty string. But I do appreciate what #132 does.
LV 2006-12-05: so, did the "[list ] " is not returning a pure list report ever get filed at tcl.sf.net?
Lars H: Yes, it is #1143805 [
1]. The reply was mostly that "we prefer it the way it is; closing report".