Replace elements in a list with new elements The documentation for this command can be found at http://www.purl.org/tcl/home/man/tcl8.5/TclCmd/lreplace.htm : '''lreplace''' ''list first last'' ?''element element ...''? '''Lreplace''' returns a new list formed by replacing one or more elements of ''list'' with the ''element'' arguments. ''First'' gives the index in ''list'' of the first element to be replaced (0 refers to the first element). If ''first'' is less than zero then it refers to the first element of ''list''; the element indicated by ''first'' must exist in the list. ''Last'' gives the index in ''list'' of the last element to be replaced. If ''last'' is less than ''first'' then no elements are deleted; the new elements are simply inserted before ''first''. ''First'' or ''last'' may be '''end''' (or any abbreviation of it) to refer to the last element of the list. The ''element'' arguments specify zero or more new arguments to be added to the list in place of those that were deleted. Each ''element'' argument will become a separate element of the list. If no ''element'' arguments are specified, then the elements between first and last are simply deleted. (from: TclHelp) ---- **Examples** % lreplace {a b c} 0 0 @ @ b c % lreplace {a b c} 1 1 a c <> If the ''last'' argument of lreplace was made optional, one could essentially just alias ldelete to lreplace [CmCc] ---- [TFW] Feb 20, 2004 - Inplace replacements Often time we have a long list we want to replace "in-place", that is without copying the list to a new altered list. Using the [K] combinator it is quite easy. (Note 8.5 is needed for the {expand} syntax) proc lipreplace {_list first last args} { upvar $_list list set list [lreplace [K $list [set list ""]] $first $last {expand}$args] } > set A [list 1 2 3] 1 2 3 > lipreplace A 1 end c d 1 c d ---- ''[escargo] 15 Sep 2005'' - Perhaps there is a better place for the following discussion, but this is where I saw a specific feature mentioned that I want to raise an issue about. '''List commands bounds checking and associated behavior''' The description above states (in part): "If ''first'' is less than zero then it refers to the first element of ''list''." I see two problems with this: * What should the behavior be when indexing outside the bounds of a list? * How does this behavior vary from other list operations? Personally, I see allowing negative indexes (''first'' or ''last'') to be errors, and ones that are ''silent failures'' at that. (This is unlike [Icon] where at least some negative indexes have semantically valid meaning.) Perhaps list operations that do indexing should have a '''-strict''' option so that if indexes are outside the proper ranges, errors would be thrown. On the second issue, [lindex] allows negative indexes (and indexes greater than the length of the list), but returns no values. The negative index is not coerced to zero. Thus the same index value (a negative one) refers to no element with [lindex] but the zeroth element with lreplace. Perhaps an item for the [Tcl 9.0 WishList] would be consistent behavior for [list] and [string] indexing semantics. ---- [AMG]: While [[lreplace]] can be used to prepend elements to the beginning of a list, it cannot be used to append elements to the end of a list. ====== lreplace {0 1 2} 0 -1 x y z → x y z 0 1 2 lreplace {0 1 2} end -1 x y z → 0 1 x y z 2 lreplace {0 1 2} end+1 -1 x y z → error: list doesn't contain element end+1 ====== The man page says "if ''last'' is less than ''first'', then any specified elements will be inserted into the list at the point specified by ''first'' with no elements being deleted." Like [[[lindex]]], it refers to [[[string index]]] for an explanation of the index notation and interpretation, so '''end''' is the last element, which is '''2''' in this case. Clearly, the insertion takes place ''just before'' the ''first'' element, even when ''first'' is '''end'''-relative. This is inconsistent with [[[linsert]]], which (despite the documentation) inserts ''just after'' the ''index'''th element when ''index'' is '''end'''-relative. It is also inconsistent that [[lreplace]] accepts indexes before the beginning of the list but rejects indexes after the end of the list. [[[linsert]]] accepts out-of-bounds indexes in either direction. By the way, to prepend and append individual elements or entire lists to a list, several combinations of [[[concat]]], [[[list]]], and [{*}] can be used. Or if in-place modification is desired, use [[[lappend]]] with or without [{*}], or use [[[lset]]] one element at a time. For example, all of the following combinations return '''{x y 0 1}''': ====== set elem1 0; set elem2 1 set list1 {x y}; set list2 {0 1} ====== %| | |% &| Combine lists and elements using '''concat''' and '''list''' | `concat $list1 [[list $elem1]] [[list $elem2]]` |& &| Combine lists using '''concat''' | `concat $list1 $list2` |& %| | |% &| Combine lists and elements using '''list''' and '''{*}''' | `list {*}$list1 $elem1 $elem2` |& &| Combine lists using '''list''' and '''{*}''' | `list {*}$list1 {*}$list2` |& %| | |% &| Append elements to a list using '''lappend''' | `lappend list1 $elem1 $elem2` |& &| Append a list to a list using '''lappend''' and '''{*}''' | `lappend list1 {*}$list2` |& %| | |% &| Append elements to a list using '''lset''' | `lset list1 end+1 $elem1; lset list1 end+1 $elem2` |& %| | |% : <> ---- **See also** * [linsert] * [lappend] * [list] <> Command