I'd like to find elisp's analog of:
sum(n for n in numbers if n % 2) # Python
numbers.select { |n| n % 2 != 0 }.inject { |a, b| a + b } # Ruby
Imperative way:
(defun oddp (number)
(not (= (mod number 2) 0)))
(defun sum-odd-with-dolist (list)
(let ((acc 0))
(dolist (item list acc)
(if (oddp item)
(setq acc (+ item acc))))))
From Porting Common Lisp:
(defun sum-odd-with-dolist-incr (list)
(let ((total 0))
(dolist (item list)
(if (oddp item)
(incf total item)))
total))
Using 'cl-*
' loop
:
(defun sum-odd-with-loop (list)
(loop for x in list if (oddp x) sum x))
(sum-odd-with-loop '(1 2 3))
4
Is there a more idiomatic way to do it (that does not require cl-*
packages)?
How to sum a list of numbers in Emacs Lisp?
The idiomatic way to do it is to use the functions and macros in the cl
packages. They come as standard with Emacs Lisp and there's nothing wrong with using them.
I doubt you'll find a way to do it that's as terse and clear as
(loop for x in list if (oddp x) sum x)
There are more functional ways to do it, such as
(apply #'+ (remove-if-not #'oddp list))
but this uses remove-if-not
which is from the cl-seq
package. You could write out a loop by hand:
(let ((sum 0)) (dolist (x list sum) (when (oddp x) (incf sum x))))
but this uses dolist
and incf
which are both in the cl-macs
package. Basically you can't escape the cl
package: oddp
itself is a cl
function!
My best effort using absolutely no cl
facilities is this:
(apply #'+ (mapcar (lambda (x) (* x (mod x 2))) list))
but it would absurd to use this in practice instead of the (loop ...)
version.
(apply '+ (delq nil (mapcar (lambda (x) (and (= 1 (% x 2)) x)) '(1 2 3 4 5))))
I agree with Gareth Rees's answer, but if you use functional programming and data manipulation heavily in your code, i strongly recommend installing Magnar Sveen's dash.el
list API. It has ridiculous amount of functions for writing concise and elegant functional code. Incidentally, it itself is written without cl
library. Summing up odd numbers in a list would then be:
(-sum (--filter (= (mod it 2) 1) '(1 2 3 4 5)))
-sum
is short for (-reduce '+ xs)
. Functions starting with 2 hyphens are anaphoric macros, they expose a temporary variable. For example, here instead of passing (lambda (x) (= (mod x 2) 1))
to --filter
we simply write (= (mod it 2) 1)
, where it
is used for a local variable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With