Originated by Tom Wilkason on comp.lang.tcl. Modifications by [DGP]. if {[package vcompare [package provide Tcl] 8.4] < 0} { proc tcl::K {a b} {return $a} proc lset {listName index val} { upvar $listName list set list [lreplace [tcl::K $list [set list {}]] $index $index $val] } } ;# end if ---- [KPV] Does anybody have a version that works with multiple indices? (yes, see KMG 2005-Sep-03 entry below) [MG] Nov 12 2004 - Does this work? proc lset2 {listName args} { if { [llength $args] == "0" } { error "wrong # args: should be \"lset2 listVar index ?index...? value\"" } upvar $listName list if { [llength $args] == "1" || ([llength $args] == "2" && [llength [lindex $args 0]] == "0") } { set list [lindex $args [expr {[llength $args]=="1"?0:1}]] return $list; } set val [lindex $args end] foreach x [lrange $args 0 end-1] { set list [lreplace $list $x $x $val] } return $list; } [LIO] I couldn't seem to get the above to work correctly. I wrote a recursive version, the only difference to the actual lset (that I can think of) is it will not take the indeces as a single list (although it would be easy to add that in). if {[package vcompare [package provide Tcl] 8.4] < 0} { proc tcl::K {a b} {return $a} proc lset_r {list args val} { if { [llength $args] == "0" } { return $val } else { return [lreplace $list [lindex $args 0] [lindex $args 0] [lset_r [lindex $list [lindex $args 0]] [lrange $args 1 end] $val]] } } proc lset {listName args} { if { [llength $args] == "0" } { error "wrong # args: should be \"lset varName ?index...? newValue\"" } upvar $listName list set list [lset_r [tcl::K $list [set list {}]] [lrange $args 0 end-1] [lindex $args end]] } } [TP] 2005-01-12 I wrote this version a while back to use in Jacl. It probably could be optimized with the K tricks. Nor am I sure that it's fully compatible with the current 8.4 native lset. proc lset { varName args } { upvar 1 $varName list switch [llength $args] { 0 { error \ "wrong # args: should be \"lset listVar index ?index...? value\"" } 1 { set list [lindex $args 0] return $list } 2 { set index [lindex $args 0] if {[llength $index] > 1} { set value [lindex $args end] set list [eval lset list $index [list $value]] return $list } else { if {[regexp end $index]} { set index \ [expr ([llength $list]-1) [string range $index 3 end]] } if {$index < 0 || $index >= [llength $list]} { error "list index out of range" } set value [lindex $args end] set list [lreplace $list $index $index $value] return $list } } default { set index [lindex $args 0] if {[regexp end $index]} { set index [expr ([llength $list]-1) [string range $index 3 end]] } set rest [lrange $args 1 end-1] set value [lindex $args end] set sublist [lindex $list $index] set first [lrange $list 0 [expr {$index - 1}]] set last [lrange $list [expr {$index + 1}] end] set list $first lappend list [eval lset sublist $rest [list $value]] foreach l $last { lappend list $l } return $list } } } ---- [RS] 2005-02-20 hacked up this recursive multiple-index version for the [iPaq] (Keuchel's port was 8.4a2, no [lset] yet): proc lset {_list args} { upvar 1 $_list list set indices [lrange $args 0 end-1] if {[llength $indices]==1} {set indices [lindex $indices 0]} ;# list case set list [lset0 $list $indices [lindex $args end]] } proc lset0 {list indices val} { if {[llength $indices]==0} {return $val} set p [lindex $indices 0] set list2 [lindex $list $p] set ind2 [lrange $indices 1 end] lreplace $list $p $p [lset0 $list2 $ind2 $val] } #-- Test with indices in a list, or in pieces: % set x {{a b} {c d}} {a b} {c d} % lset x 0 1 e {a e} {c d} % lset x {0 1} f {a f} {c d} ---- [KMG] 2005-Sep-03 wrote this recursive multiple-index version to help backport [sugar] to 8.3. (I was too eager to solve the problem to remember to check here for an existing solution first!). This implementation passes all of the reference test cases on the 8.4 help page for 'lset'. proc lset { varName args } { upvar 1 $varName theList set theValue [lindex $args end] switch -exact [llength $args] { 0 { # lset v (do nothing) } 1 { # lset v x (copy x to v) set theList $theValue } 2 { # lset v i x (set the i'th element of v to x) # lset v {} x (set v to x) # lset v {i j k} x (set the k'th element of the j'th element of the i'th element of v to x) set indexList [lindex $args 0] set index [lindex $indexList 0] set theLength [llength $theList] switch -exact [llength $indexList] { 0 { # lset v {} x (set v to x) set theList $theValue } 1 { # lset v i x (set the i'th element of v to x) if { [string is integer -strict $index] && ($index >= $theLength) } { error "list index out of range: $index >= $theLength" } set theList [lreplace $theList $index $index $theValue] } default { # lset v {i j k} x (set the k'th element of the j'th element of the i'th element of v to x) set subList [lindex $theList $index] set subList [lset subList [lrange $indexList 1 end] $theValue] set theList [lreplace $theList $index $index $subList] } } } default { # lset v i j k x (set the k'th element of the j'th element of the i'th element of v to x) set indexList [lrange $args 0 end-1] set theList [lset theList $indexList $theValue] } } return $theList } ---- '''See Also''': [lindex forward compatibility] ---- [Category Porting]