Numeric Statistics From a List

Created by CecilWesterhof.

At a certain point I needed the maximum, minimum and mean of a list. Instead of calculating them one after the other I created a proc that calculates everything in one go. And also length and sum. (But KPV pointed out that there is ::math::statistics::basic-stats . So I do not need this any-more.

This is the proc:

proc listNumericStats thisList {
    set length [llength $thisList]
    if {$length == 0} {
        error "List cannot be empty"
    }
    set max [lindex $thisList 0]
    set min $max
    set sum 0.
    foreach element $thisList {
        set sum [expr {$sum + $element}]
        if {$element < $min} {
            set min $element
        } elseif {$element > $max} {
            set max $element
        }
    }
    dict set stats length $length
    dict set stats max    $max
    dict set stats mean   [expr {$sum / $length}]
    dict set stats min    $min
    dict set stats sum    $sum
    return $stats
}

DEC:That sounds over kill to me

set aList [ lsort -real $anotherList]
set max [ lindex $aList end]
set min [ lindex $aList 0]
set sum [expr {[join $aList "+"]}]
set len [llength $aList ] 
set mean [ expr {$sum/$len}]

DEC:I would avoid looping over a list at the script level if you can

CecilWesterhof: With your code you loop two times over the list instead of once. And you need a sort also, which is also not cheap for big lists. So I would think that my implementation is a lot more efficient.

But it is moot, because I do not need it any-more thanks to KPV.

KPV: Also checkout ::math::statistics::basic-stats

2018-08-26: Never assume.

interp alias {} listNumericStatsA {} listNumericStats

proc listNumericStatsB thisList {
    set aList [ lsort -real $thisList]
    set sum [expr [join $aList "+"]]
    dict set stats length [llength $aList] 
    dict set stats max    [lindex $aList end]
    dict set stats mean   [expr {$sum/[llength $aList]}]
    dict set stats min    [lindex $aList 0]
    dict set stats sum    $sum
    return $stats
}

proc listNumericStatsC thisList {
    set sum [::tcl::mathop::+ {*}$thisList]
    dict set stats length [llength $thisList] 
    dict set stats max    [::tcl::mathfunc::max {*}$thisList]
    dict set stats mean   [expr {$sum/[llength $thisList]}]
    dict set stats min    [::tcl::mathfunc::min {*}$thisList]
    dict set stats sum    $sum
    return $stats
}

package require math
set theList [lmap item [lrepeat 300 *] {::math::random}]

puts [expr {[listNumericStatsA $theList] eq [listNumericStatsB $theList] && [listNumericStatsA $theList] eq [listNumericStatsC $theList]}]
puts [expr {[listNumericStatsA $theList] eq [listNumericStatsC $theList]}]

time {listNumericStatsA $theList} 10000
time {listNumericStatsB $theList} 10000
time {listNumericStatsC $theList} 10000
0
1
102.5553 microseconds per iteration
956.2068 microseconds per iteration
367.4345 microseconds per iteration