SetOps, Intersect3, Timing Script

# -*- tcl -*-

 # test = intersection + differences

 set max 50

 proc testA {a b} {
    if {[llength $a] == 0} {
        return [list {} {} $b]
    }
    if {[llength $b] == 0} {
        return [list {} $a {}]
    }

    set res_is {}
    set res_ab {}
    set res_ba {}

    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, add to intersection.
            lappend res_is [lindex $a 0]
            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 B-A.
            lappend res_ba [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 A-B.
            lappend res_ab [lindex $a 0]
            set a [lrange $a 1 end]
        }
        if {[llength $a] == 0} {
            foreach e $b {
                lappend res_ba $e
            }

            return [list $res_is $res_ab $res_ba]
        }
        if {[llength $b] == 0} {
            foreach e $a {
                lappend res_ab $e
            }

            return [list $res_is $res_ab $res_ba]
        }
    }

    return [list $res_is $res_ab $res_ba]
 }


 proc testC {a b} {
    if {[llength $a] == 0} {
        return [list {} {} $b]
    }
    if {[llength $b] == 0} {
        return [list {} $a {}]
    }

    set res_i  {}
    set res_ab {}
    set res_ba {}

    foreach e $b {
        set ba($e) .
    }

    foreach e $a {
        set aa($e) .
    }

    foreach e $a {
        if {![info exists ba($e)]} {
            lappend res_ab $e
        } else {
            lappend res_i $e
        }
    }

    foreach e $b {
        if {![info exists aa($e)]} {
            lappend res_ba $e
        } else {
            lappend res_i $e
        }
    }

    list $res_i $res_ab $res_ba
 }


 proc Intersect2 {a b} {
    if {[llength $a] == 0} {
        return {}
    }
    if {[llength $b] == 0} {
        return {}
    }

    set res {}

    if {[llength $a] < [llength $b]} {
        foreach $b {.} {break}

        foreach e $a {
            if {[info exists $e]} {
                lappend res $e
            }
        }
    } else {
        foreach $a {.} {break}

        foreach e $b {
            if {[info exists $e]} {
                lappend res $e
            }
        }
    }

    return $res
 }


 proc diff {a b} {
    if {[llength $a] == 0} {
        return {}
    }
    if {[llength $b] == 0} {
        return $a
    }

    set res {}

    foreach $b {.} {break}

    foreach e $a {
        if {![info exists $e]} {
            lappend res $e
        }
    }

    return $res
 }


 proc testB {a b} {
    list [Intersect2 $a $b] [diff $a $b] [diff $b $a]
 }



 # IS_NE -> a, b   random, unsorted, intersection almost always empty
 # IS_EQ -> a = b, random

 set fa1  [open "|./2nep IS_A_NE Ar.dat   X.dat" w]
 set fa2  [open "|./2nep IS_A_EQ Ae0.dat  X.dat" w]
 set fb1  [open "|./2nep IS_B_NE Br.dat   X.dat" w]
 set fb2  [open "|./2nep IS_B_EQ Be0.dat  X.dat" w]
 set fc1  [open "|./2nep IS_C_NE Cr.dat   X.dat" w]
 set fc2  [open "|./2nep IS_C_EQ Ce0.dat  X.dat" w]
 set fx   [open "|./2nep IS_X    X.dat" w]

 set a0 {}
 set b0 {}

 puts stdout " ______________________________" ; flush stdout
 puts stdout " ISECT| ......A ......B ......C" ; flush stdout

 for {set i 0} {$i <= $max} {incr i} {

    set ix [format %03d $i]

    puts stderr "   * $ix (a0) =  $a0" ; flush stderr
    puts stderr "   * $ix (b0) =  $b0" ; flush stderr

    set ra1  [lindex [time {testA $a0 $b0} 1000] 0]
    set ra2  [lindex [time {testA $a0 $a0} 1000] 0]

    set rb1  [lindex [time {testB $a0 $b0} 1000] 0]
    set rb2  [lindex [time {testB $a0 $a0} 1000] 0]

    set rc1  [lindex [time {testC $a0 $b0} 1000] 0]
    set rc2  [lindex [time {testC $a0 $a0} 1000] 0]

    puts stdout " ______________________________" ; flush stdout
    puts stdout " $ix NE [format %7d $ra1] [format %7d $rb1] [format %7d $rc1]"
    puts stdout " $ix EQ [format %7d $ra2] [format %7d $rb2] [format %7d $rc2]"

    puts $fa1 $ra1
    puts $fa2 $ra2

    puts $fb1 $rb1
    puts $fb2 $rb2

    puts $fc1 $rc1
    puts $fc2 $rc2

    puts $fx  $i

    lappend a0 [string range [lindex [split [expr {rand()}] .] 1] 0 4]
    lappend b0 [string range [lindex [split [expr {rand()}] .] 1] 0 4]
 }


 puts stderr "----"     ; flush stderr
 puts stdout " ______________________" ; flush stdout

 close $fa1
 close $fa2

 close $fb1
 close $fb2

 close $fc1
 close $fc2

 close $fx