Replace elements in a list with new elements
Documentation edit
- man page

Synopsis edit
-
- lreplace list first last ?element element ...?
Description edit
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 edit
% lreplace {a b c} 0 0 @
@ b c
% lreplace {a b c} 1 1
a c In-place Modification of the List edit
Given the following code:
set l [lreplace $l $j $j $newvalue]
The current bytecode compiler tries to allow for the possibility that there could be an error between the invocation of
[lreplace] and the invocation of set. Thus, two copies of the list l are needed (one before, one after). For more discussion of this topic, see
Shuffle a list, and
lset.
When the list is so large that memory consumption may be an issue, there is a trick that can be used to get
Tcl to re-use the list as the return value, avoiding duplication of the list:
set l [lreplace $l[set l {}] $j $j $newvalue]This works because Tcl observes that the reference count of the original value of
l has dropped to zero, so that object may be re-used for arbitrary purposes. Tcl jumps on the opportunity and re-uses it.
The following procedure accomplishes the same thing
proc lipreplace {_list first last args} {
upvar $_list list
set list [lreplace [K $list [set list {}]] $first $last {*}$args]
}% set A [list 1 2 3]
1 2 3
% lipreplace A 1 end c d
1 c d
Bounds Checking edit
escargo 2005-09-15: 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 behaviorThe 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.
Prepend, Yes, Append, No edit
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+1The 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 |
| | |
|---|
-
If the
last argument of lreplace was made optional, one could essentially just alias ldelete to lreplace
CmCc See Also edit
- linsert
- lappend
- list