Purpose: Definition and discussion of set functionality, especially the function to compute the symmetrical difference of two sets. Symmetrical difference being the set containing those elements which are in one of the sets, but not the other, the inverse of intersection.
::setops::symdiff set1 set2
Arguments:
Result:
Implementation:
Several variants are possible:
Possible shortcuts:
Timing information:
Summary:
Variant A.
proc ::setops::symdiff {a b} {
if {[llength $a] == 0} { return $b } if {[llength $b] == 0} { return $a } set res {} set a [lsort $a] set b [lsort $b] while {1} { # Store lindex/0,1 in var, access later faster ? set n [string compare [lindex $a 0] [lindex $b 0]] if {$n == 0} { # A = B => element in both, so not in sym. difference set a [lrange $a 1 end] set b [lrange $b 1 end] } elseif {$n > 0} { # A > B, remove B, we are beyond the element. # This element in B is part of the result too. lappend res [lindex $b 0] set b [lrange $b 1 end] } else { # A < B, remove A, we are beyond the element. # This element in A is part of the result too. lappend res [lindex $a 0] set a [lrange $a 1 end] } if {[llength $a] == 0} { foreach e $b { lappend res $e } return $res } if {[llength $b] == 0} { foreach e $a { lappend res $e } return $res } } return $res
}
Variant B.
proc ::setops::symdiff {a b} { if {[llength $a] == 0} { return $b } if {[llength $b] == 0} { return $a } set res {} foreach e $a { set aa($e) . } foreach e $b { set ba($e) . } foreach e $a { if {[info exists aa($e)] != [info exists ba($e)]} { lappend res $e } } foreach e $b { if {[info exists aa($e)] != [info exists ba($e)]} { lappend res $e } } return $res }
Variant C.
proc ::setops::symdiff {a b} { if {[llength $a] == 0} { return $b } if {[llength $b] == 0} { return $a } set res {} foreach e $a { set aa($e) . } foreach e $b { set ba($e) . } foreach e $a { if {![info exists ba($e)]} { lappend res $e } } foreach e $b { if {![info exists aa($e)]} { lappend res $e } } return $res }
Variant D.
proc ::setops::symdiff {a b} { diff [union $a $b] [Intersect2 $a $b] }
-- AK