Summing a list

Purpose: example of code to apply the arithmetic sum operation to all elements of a list.

As of Tcl 8.5, one preferably uses the tcl::mathop::+ command and {*}:

proc ladd {l} {::tcl::mathop::+ {*}$l}

Before that, other techniques were necessary...


# Pass ladd a list and receive back a single value which is a total of
# all the elements.  WARNING: assumes all elements are integer.
proc ladd {l} {
    set total 0
    foreach nxt $l {
        incr total $nxt
    }
    return $total
}

Do you think it would be harmful to students to see

proc ladd l {
    if {![llength $l]} {return 0}
    return [expr [join $l +]]
}

?


Harmful? Probably not. If it is faster, that would be fine. Now you can add doubles as well, but the overflow warning still applies ... Use of Mpexpr or some other extended math package is required to get around the innate limitations based on Tcl's implicit use of C numeric types. (The comments above also used to warn about not preventing overflow, but overflow from adding numbers isn't much of an issue in Tcl 8.5+, either.)


You can get even more functional and elegant if you append a dummy "+0", so an empty list causes no problems (and needs not to be tested):

proc ladd L {expr [join $L +]+0} ;# RS

AM (11 june 2010) The form with the expand operation ({*}) requires no checking either.


Using join is very elegant but it gives me serious performance issues in Tcl 8.4 if the list has a couple of thousand entries. Using a simple foreach increased the speed by factors of up to 500 (depending on the size of the list and the size of the integers in the list). ManUml


See also: Sample math programs - Arts and crafts of Tcl-Tk programming


OdinVanguard - 2016-04-13 17:57:18

why not use expr inside the for loop so it will handle non-integers?

e.g.

proc ladd {l} {set total 0.0; foreach nxt $l {set total [expr $total + $nxt]}; return $total}

would this be slower than the incr version?

PYK 2016-04-13 23:45: The performance hit of not bracing the expression will dwarf any other factor. This is better:

proc ladd {l} {set total 0.0; foreach nxt $l {set total [expr {$total + $nxt}]}; return $total}