concat

Difference between version 55 and 56 - Previous - Next
'''[http://www.tcl.tk/man/tcl/TclCmd/concat.htm%|%concat]''', a [Tcl Commands%|%built-in] [command], joins strings together.  If the strings are
lists, the effect is to join the lists together.



** Synopsis **

    :   '''concat''' ?''arg arg ...''?



** Description **
T'''concat''' trims the leading and trailing whitespace from theach argument,
dis canrds joiall arguments that aftem
r torimming are the empty string, andd then joins
the remaining arguments wtogether with a single space between theach pair of
arguments. I The result of `concallt` withe no arguments are lis the empty s,
thrisng. has tThe
procedure is named effe`[ct as concat]` bencating thusem intos ma sing (only?) use list, hence the
name,o "concat".  Whente
lists: If all the arguments are not well-formed lists, the result may
notis be a well-fist cormposed of all the
ist ems in ther, bgiven lists.  Due to the strategy isof [definoe errors raout of
existence%|%d.efining errors [[out of existence], `concat`]
 opermiates aony anumbey
strings, noft argjumenst lists.  With eno the arguments are not lists, the result may not
be a list, anor emay happen ty
o be a listri, but ngot the list that was expected. 
[Lars H]: [[PYK]: `conc[evat`l]` iforms indtheed def[scrinedpt] as an top ervaluatione by con gcateneral string its
(partly becagusme int is jusedt also by [[`[evconcalt]`] does, whichand oif then operates on sultr ings
in a not-q[pure liste-%|%list m
thanner).t However, when alls argumento string are [pure lisent]s atheion
] it can taskip the a [shorubstcitution] step since
such a list avoids working owin tho contheain no substritutiongs, rewhich improves pentatirformansce.

For pure list concatenation, use `[{*}]`:

======
# Instead of: set foo [concat $bar $boo $spong]
set foo [list {*}$bar {*}$boo {*}$spong]
======



** Documentation **
   [http://www.tcl-lang.tkorg/man/tcl/TclCmd/concat.htm%|%official reference]:   



** See Also ** 

   [list]:   

   [append]:   



** Examples **

======
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 list]s.  See
[http://core.tcl.tk/tcl/artifact?filename=generic/tclUtil.c&ci=trunk%|%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:

   * string substitution

======
set a abc
set b 127
set c $a$b
======

   * [[`[format]`]

======
set c [format {%s %s} $a $b]
======

   * [[`[append]`] (for strings)

   * [[`[lappend]`] (for lists)

   * [[`[join]`]

======
join [list $string1 $string2]
======


======
set list [concat {} a b]
llength $list ;# -> 2
set list [concat {{}} a b]
llength $list ;# -> 3
======



** Performance **

[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]:

======none
% 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:
   1. 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.
   2. 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 **
Concatenating the sublists of a list (e.g. a matrix) is best done with
`[join]`.  However, `[concat]` can also be used as follows:

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[set matrix {}] 0 concat]
======

In most reasonable cases,

======eval [list concat] $matrix
======
will works 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** His a rather controversical statement. An obvioDus 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 maximNum, then this will even result in loss of precision for numerical
data when the numbePr 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.**
'''The conversation below is about an issue that was fixed in Tcl [Changes in
Tcl/Tk 8.5%|%version 8.5].'''
The issue wasn't specifically about `[concat]`,  and the example discussed is a
rather verbose way of illustrating that in older versions of Tcl the string
representation of a floating point number wasn't always precise enough to
unambiguously reflect the number.  For example, the string representation of
`[expr] {1.0 / 3.0}` was previously
** Numerical Precision **======
0.333333333333
======
, whereas in later versions it is

======
0.3333333333333333
======

----

[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] [http://tip.tcl.tk/132.html%|%#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
[http://sourceforge.net/tracker/index.php?func=detail&aid=1143805&group_id=10894&atid=110894].
The reply was mostly that "we prefer it the way it is; closing report".


** Page Authors **
   [Lars H]:  Offered comments on floating point precision and `[eval]`. 

   [PYK]:   Noted the historical nature of the issues regaring the precision of the string representation of floating point numbers.




<<categories>> syntax | Arts and crafts of Tcl-Tk programming | Command | String Processing