set operations for Tcl lists

SS 30Nov2004: The following commands are basic set operations for Tcl lists. They are part of a larger library for functional programming in Tcl that's possible to find at [L1 ]. The proposed commands try to run in O(M+N) time complexity, and to don't mess with the order of the elements when possible.

 proc lintersect {a b} {
     foreach e $a {
         set x($e) {}
     }
     set result {}
     foreach e $b {
         if {[info exists x($e)]} {
             lappend result $e
         }
     }
     return $result
 }
 
 proc lunion {a b} {
     foreach e $a {
         set x($e) {}
     }
     foreach e $b {
         if {![info exists x($e)]} {
             lappend a $e
         }
     }
     return $a
 }
 
 proc ldifference {a b} {
     foreach e $b {
         set x($e) {}
     }
     set result {}
     foreach e $a {
         if {![info exists x($e)]} {
             lappend result $e
         }
     }
     return $result
 }
 
 proc in {list element} {
     expr {[lsearch -exact $list $element] != -1}
 }

MJ - Using 8.5 ni and in, this can be speeded up quite considerable, for instance:

 proc ldifference2 {a b} {
     set result {}
     foreach e $a {
         if {$e ni $b} {lappend result $e}
     }
     return $result
 }

zashi - The above example using ni doesn't work if $b has more elements than $a. APN I think you are confusing the difference operation. It returns A-B, i.e. all elements of A that are not also in B. It is not "all values that are in A or B but not both".

You can also use lmap to make this more concise. But then to fix the length issue it gets bigger again

  proc ldifference3  {a b} {
    if {[llength $a] > [llength $b]} {
      return [lmap e $a {if {$e ni $b} {set e} else continue}]
    } else {
      return [lmap e $b {if {$e ni $a} {set e} else continue}]
    }
  }