Version 8 of lremove

Updated 2006-11-17 08:26:42

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

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 {}

See also list


Category Command