How to remove items from a list not by their position ([lreplace]) but by the actual content. My solution would be: proc K { x y } { set x } proc lremove { listvar string } { upvar $listvar in foreach item [K $in [set in [list]]] { if {[string equal $item $string]} { continue } lappend in $item } } which gives us % set a [list a b c a b c a b c] a b c a b c a b c % lremove a b % set a a c a c a c Is there any reason not to do it that way? Gotisch ---- [RS] proposes this built-in way, waving many flags :) % set a [lsearch -all -inline -not -exact $a b] a c a c a c [wdb] Simply ingenious! ---- Todd A. Jacobs suggests this slightly more flexible version: # lremove ?-all? list pattern # # Removes matching elements from a list, and returns a new list. proc lremove {args} { if {[llength $args] < 2} { puts stderr {Wrong # args: should be "lremove ?-all? list pattern"} } set list [lindex $args end-1] set elements [lindex $args end] if [string match -all [lindex $args 0]] { foreach element $elements { set list [lsearch -all -inline -not -exact $list $element] } } else { # Using lreplace to truncate the list saves having to calculate # ranges or offsets from the indexed element. The trimming is # necessary in cases where the first or last element is the # indexed element. foreach element $elements { set idx [lsearch $list $element] set list [string trim \ "[lreplace $list $idx end] [lreplace $list 0 $idx]"] } } return $list } # Test cases. set foo {1 2 3 4 5 6 7 8 9 10} puts "Foo: [list $foo]" puts "Foo: replace one: [lremove $foo $argv]" puts "Foo: replace all: [lremove -all $foo $argv]" puts {} set bar {1 2 3 4 1 6 7 1 9 10} puts "Bar: [list $bar]" puts "Bar: replace one: [lremove $bar $argv]" puts "Bar: replace all: [lremove -all $bar $argv]" [dzach] ...but then, when I do : set bar {1 2 3 {} 4 1 6 7 1 9 10 {}} lremove -all $bar {} I still get: 1 2 3 {} 4 1 6 7 1 9 10 {} [jmn] this is because the proc expects a *list* of patterns as the 2nd argument. Try instead: lremove -all $bar [list {}] I don't see why the complicated 'lreplace' line with the 'string trim' is required. As far as I can see - it could be replaced with: set list [lreplace $list $idx $idx] When removing a single value (1st encountered match) from a list - I use: set posn [lsearch -exact $list $val] set list [lreplace $list $posn $posn] This is slightly different in functionality from RS's beautiful one liner above, which removes all instances. If you know you only have one instance of the value to be removed - this 2 liner may be slightly faster on large lists (tested on Tcl8.6b1).. but on a 2007 vintage machine we're talking maybe a couple of hundred microseconds for lists even of size approx 10K, so it's not likely to be an issue except for some pretty intensive inner loops with large lists. [milarepa] How about this: ====== proc lremove {list match} { set idx_list [lsearch -all $list $match] foreach idx [lreverse $idx_list] { set list [lreplace $list $idx $idx] } return $list } ====== [gold] Multiple entries, using Suchenworth's idea: ====== # written on Windows XP on eTCL # working under TCL version 8.5.6 and eTCL 1.0.1 # gold on TCL WIKI , 3jul2013 package require Tk proc cleaner {target args} { set res $target foreach unwant [split $args ] { # suchenworth idea set res [lsearch -all -inline -not -exact $res $unwant ]} return $res } console show set a_target_list [list a b c a b c a b c 1234 1234 5678] puts " [cleaner {a b c a b c a b c} b c]" puts " [cleaner $a_target_list 1234 5678]" ====== ---- See also * [list] * [http://tip.tcl.tk/367.html%|%TIP #367] <> Command