# ---------------------------------------------
# SetOps -- Set operations for Tcl
#
# (C) c.l.t. community, 1999
#
# $Id: 359,v 1.5 2003-09-18 08:00:06 jcw Exp $
# ---------------------------------------------
# Implementation variant for tcl 8.x and beyond.
# Uses namespaces.
# ---------------------------------------------
proc ::setops::create {args} {
if {[llength $args] == 0} {
return {}
}
foreach $args {.} {break}
unset args
info locals
}
proc ::setops::contains {set element} {
expr {[lsearch -exact $set $element] < 0 ? 0 : 1}
}
proc ::setops::union {args} {
switch [llength $args] {
0 {
return {}
}
1 {
return [lindex $args 0]
}
default {
foreach __SETA__ $args {
if {[llength $__SETA__] > 0} {
foreach $__SETA__ {.} {break}
}
}
unset args __SETA__
info locals
}
}
}
proc ::setops::Intersect2 {__SETA__ __SETB__} {
if {[llength $__SETA__] == 0} {
return {}
}
if {[llength $__SETB__] == 0} {
return {}
}
set __RESULT__ {}
if {[llength $__SETA__] < [llength $__SETB__]} {
foreach $__SETB__ {.} {break}
foreach __ITEM__ $__SETA__ {
if {[info exists $__ITEM__]} {
lappend __RESULT__ $__ITEM__
}
}
} else {
foreach $__SETA__ {.} {break}
foreach __ITEM__ $__SETB__ {
if {[info exists $__ITEM__]} {
lappend __RESULT__ $__ITEM__
}
}
}
return $__RESULT__
}
proc ::setops::intersect {args} {
switch [llength $args] {
0 {
# Intersection of nothing is nothing
return {}
}
1 {
return [lindex $args 0]
}
default {
set res [lindex $args 0]
set args [lrange $args 1 end]
while {($res != {}) && ([llength $args] > 0)} {
set res [Intersect2 $res [lindex $args 0]]
set args [lrange $args 1 end]
}
return $res
}
}
}
proc ::setops::diff {__SETA__ __SETB__} {
if {[llength $__SETA__] == 0} {
return {}
}
if {[llength $__SETB__] == 0} {
return $__SETA__
}
set __RESULT__ {}
foreach $__SETB__ {.} {break}
foreach __ITEM__ $__SETA__ {
if {![info exists $__ITEM__]} {
lappend __RESULT__ $__ITEM__
}
}
return $__RESULT__
}
proc ::setops::symdiff {a b} {
diff [union $a $b] [Intersect2 $a $b]
}
proc ::setops::empty {set} {
expr {[llength $set] == 0}
}The above code does not work if the set elements look syntactically like array variables. For example
setops::union {a b} {c b foo(local)}returnsfoo a b cThe problem is use of local variables (optimization) instead of an explicit array. Neat trick but doesn't quite work. APN

