Tcl Part I · Module 6 · Lists
linsert and lreplace
Two commands change a list somewhere other than the end: one puts elements in at a position, the other swaps out or removes a span. They are straightforward, and they come with the module's one genuine inconsistency — unlike lappend, neither of them touches your variable. They compute a new list and hand it back, and forgetting to store it is the single most common way to write code here that appears to do nothing at all.
Foundation10 min readTclPart IListsModification
Part I · Module 6 · Chapter 6.7 · linsert and lreplace
1. The Two Commands
set l {a b c d}
puts "linsert 0 -> [linsert $l 0 header]"
puts "linsert 2 -> [linsert $l 2 X]"
puts "linsert end-> [linsert $l end X]"
puts "lreplace -> [lreplace $l 1 2 X]"linsert 0 -> header a b c d
linsert 2 -> a b X c d
linsert end-> a b c d X
lreplace -> a X dlinsert puts elements before the given position. lreplace swaps out the span between two positions, both inclusive — the same index rules as Chapter 6.5.
2. Neither Modifies the Variable
set l {a b c d}
linsert $l 0 header
lreplace $l 1 2 X
puts "unchanged: $l"
set l [linsert $l 0 header]
puts "stored: $l"unchanged: a b c d
stored: header a b c dThe first two lines computed results and threw them away — Chapter 1.5 §3.
This is the module's one real inconsistency, so it is worth having the whole picture in one place:
| Command | Modifies the variable? |
|---|---|
lappend | yes |
lset | yes |
linsert | no — returns a new list |
lreplace | no — returns a new list |
lsort | no — returns a new list |
lrange | no — returns a new list |
lindex | no — reads only |
The two that write take a variable name; the ones that return take a value. That is the tell:
lappend l "x" ;# name — modifies
set l [linsert $l 0 "x"] ;# value — returns3. Deleting With lreplace
Omit the replacement and the span is removed:
set l {a b c d}
puts "delete 1 to 2 -> [lreplace $l 1 2]"
puts "delete just 2 -> [lreplace $l 2 2]"
puts "delete last -> [lreplace $l end end]"delete 1 to 2 -> a d
delete just 2 -> a b d
delete last -> a b cThis is the standard way to remove elements, and it is not obvious from the command's name. There is no ldelete.
The pattern for removing one element by position:
set queue {alpha beta gamma}
set queue [lreplace $queue 1 1]
puts $queuealpha gammaAnd combined with a search — Chapter 6.9 — to remove by value:
set queue {alpha beta gamma}
set i [lsearch -exact $queue beta]
if {$i >= 0} {
set queue [lreplace $queue $i $i]
}
puts $queuealpha gammaThe >= 0 check is Chapter 6.9's discipline; without it a missing value gives -1 and lreplace $queue -1 -1 would do something you did not intend.
4. The Replacement Need Not Be the Same Size
set l {a b c d}
puts "2 for 1 -> [lreplace $l 1 1 X Y]"
puts "1 for 2 -> [lreplace $l 1 2 X]"
puts "0 for 2 -> [lreplace $l 1 2]"2 for 1 -> a X Y c d
1 for 2 -> a X d
0 for 2 -> a dAny number of replacement values, including none.
5. Inserting Several
set l {a d}
puts [linsert $l 1 b c]a b c dEach argument becomes one element, quoted as needed — Chapter 6.2's rule again:
set l {a d}
set result [linsert $l 1 "b c"]
puts "<$result> -> [llength $result] elements"<a {b c} d> -> 3 elementsOne element containing a space, not two elements.
6. Position Shortcuts
set l {b c}
puts "at 0 -> [linsert $l 0 a]"
puts "at end -> [linsert $l end d]"at 0 -> a b c
at end -> b c d0 prepends and end appends.
For appending, though, prefer lappend — it is shorter, it modifies the variable directly, and it does not require you to remember to store the result.
set l {b c}
set l [linsert $l end d] ;# works
lappend l e ;# shorter, and writes in place
puts $lb c d e7. Which to Use
| You want | Use |
|---|---|
| add to the end | lappend |
| add at the front | set l [linsert $l 0 ...] |
| add in the middle | set l [linsert $l $i ...] |
| change one element | lset |
| change a span | set l [lreplace $l $i $j ...] |
| remove elements | set l [lreplace $l $i $j] |
lset is the next chapter and is the better choice for changing a single element, because it modifies the variable and does not rebuild the list.
8. Common Mistakes
Forgetting to store the result. §2. The main one.
Looking for ldelete. It is lreplace with no replacement. §3.
Using a search result without checking for -1. §3.
Using linsert ... end to append. lappend is shorter and writes in place. §6.
Expecting lreplace to need a same-sized replacement. Any number works. §4.
Inserting a list expecting it to merge. linsert $l 0 $other inserts one element. Use {*} — Chapter 6.13.
9. Exercises
Exercise 1 — insert three ways. From {b c}, produce a b c, b X c and b c d, each with one linsert.
Exercise 2 — the silent no-op. Write lreplace $l 0 0 on its own line and confirm the list is unchanged. Then make it take effect.
Exercise 3 — delete. From {a b c d e}, remove element 2, then the last element, then elements 1 to 2 — three separate statements, each storing the result.
Exercise 4 — remove by value. Remove gamma from a five-element list using lsearch and lreplace, with the -1 check. Then run it again with a value that is not present and confirm nothing breaks.
Exercise 5 — resize. Replace one element with three, and three elements with one. Print the lengths before and after each.
Exercise 6 — the quoting. Insert the two-word value "b c" into {a d} at position 1. Confirm the result has three elements, not four.
10. Remember
linsert list index value ...inserts before the index;0prepends,endappends.lreplace list first last ?value ...?replaces a span, both ends inclusive.- Neither modifies the variable. Both return a new list — store it.
- Only
lappendandlsetwrite to the variable. The tell is whether the command takes a name or a value. lreplacewith no replacement deletes. There is noldelete.- The replacement can be any size, including empty.
- Inserted values are quoted as elements, so a value with spaces stays one element.
- Prefer
lappendfor appending andlsetfor changing one element.
Next: the other command that writes to the variable.
Where this fits
Part of the Tcl curriculum.
