pierson@mist (Dan Pierson) (03/21/89)
Several months ago someone asked for GNU Emacs code to sum a column of numbers. I needed such a thing today, so here it is: (defun sum-column (start end) "Display and return the sum of the integers in the rectangle delimited by START (point) and END (mark)." (interactive "d\nm") (let* ((str-nums (if (< start end) (extract-rectangle start end) (extract-rectangle end start))) (nums (mapcar '(lambda (x) (string-to-int x)) str-nums)) (sum (apply '+ nums))) (message "%d" sum) sum)) -- dan In real life: Dan Pierson, Encore Computer Corporation, Research UUCP: {talcott,linus,necis,decvax}!encore!pierson Internet: pierson@encore.com
bard@THEORY.LCS.MIT.EDU (03/21/89)
Here's a trivially improved version of Dan Pierson's sum-column function. The improvements are more as advice about gnumacs-lisp coding than significant ones: (1) using (interactive "r") instead of (interactive "d\nm") and then figuring out which is the beginning and which the end (2) eta-reducing the '(lambda (x) (string-to-int x)) into (function string-to-int). (function is like quote, but possibly better for the compiler.) (3) Only printing the result when it's called interactively, so that other programs can call it without cluttering up the message-line with random "The sum is 78" messages. Ever wonder why monkey-mode keeps saying "Done" when it is obviously not done? There's also a very cheap sum-region command, which adds up all the numbers in the region. It's not very smart; e.g., I got lazy about treating "- 1" and "-1" the same. (The second one is -1; the first is +1.) Improvements are welcome. It would be nice to have (e.g.) rational arithmetic commands, so that you could type 4/3 + (2*3)/(8+1) and run m-x eval-rational-expression-insert, and it would replace that expression by 2. (Assuming I've done it right.) Even adding up lists of numbers with decimals would be nice -- "You owe me 4.12+51.00+40.30" -- Bard the emacs gargoyle ------------ snip here ------------ (defun sum-column (start end) "Return the sum of the integers in the rectangle delimited by START and END. Interactively, it prints the sum as well, and uses the region." (interactive "r") (let* ((str-nums (extract-rectangle start end)) (nums (mapcar (function string-to-int) str-nums)) (sum (apply (function +) nums))) (if (interactive-p) (message "%d" sum)) sum)) (defun sum-region (start end) "Adds up the numbers in the region START to END. Primitive as yet. If called interactively, uses the region and prints the sum in a message. Ignores things that aren't numbers or signs, so $1 + $4 will sum to 5, and 1 -4 will sum to -3. Of course, it's really dumb, and things like 2*3 - 5 will sum to 2+3+5 = 10 -- as will 2 + 3.5. Improvements welcomed." (interactive "r") (save-excursion (goto-char start) (let ((sum 0) sign number) (while (re-search-forward "\\(-?\\)\\([0-9]+\\)" end t) ;; maybe allow whitespace between sign and number? ;; that's why I'm parsing clumsily. (setq sign (= (match-beginning 1) (match-end 1)) number (string-to-int (buffer-substring (match-beginning 2) (match-end 2)))) (setq sum (if sign (+ sum number) (- sum number)))) (if (interactive-p) (message "The sum is %d" sum)) sum)))
liberte@m.cs.uiuc.edu (03/22/89)
> /* Written 6:40 pm Mar 20, 1989 by bard@THEORY.LCS.MIT.EDU in m.cs.uiuc.edu:comp.emacs */ > (2) eta-reducing the '(lambda (x) (string-to-int x)) into > (function string-to-int). (function is like quote, but > possibly better for the compiler.) Using (function string-to-int) causes the byte-compiler to generate byte-code that dereferences the function cell of 'string-to-int. But since application of this function also causes dereferencing of the symbol - but in C code - I would expect that it is faster to let the C code to it. Therefore, (function string-to-int) would be slightly *slower* than 'string-to-int in byte-code. Where the function special form is useful is in things like: (function (lambda (x) (foo (bar x)))) This allows the byte-compiler to byte compile the lambda expression since it is expected to be used as a function. Dan LaLiberte uiucdcs!liberte liberte@cs.uiuc.edu liberte%a.cs.uiuc.edu@uiucvmd.bitnet