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)?
Related:
-
(apply '+ (delq nil (mapcar (lambda (x) (and (= 1 (% x 2)) x)) '(1 2 3 4 5))))J.F. Sebastian : Does it copy the whole list if the first argument is even?rzab : There is no arguments, i've wrote just an expression. And what it does is this: it filters the list and then applies '+. Filtering constructs new list, indeed. Anyway, the result does not rely on first argument being even or odd. So i'm not sure i understand your question right..J.F. Sebastian : s/argument/1st element of the list/. Documentation for `delq` says that it can't delete the first element in-place (or I've misunderstood something).rzab : I was completely wrong about delq, it may modify the list in case "object" is not the first element. So, would remq be proper, as it creates a new list?rzab : Although, mapcar constructs new list just for delq/remq, so original list stays intact.rzab : So, yeah, anyway, thanks for pointing out the modifying effect of delq :) -
The idiomatic way to do it is to use the functions and macros in the
clpackages. 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-notwhich is from thecl-seqpackage. You could write out a loop by hand:(let ((sum 0)) (dolist (x list sum) (when (oddp x) (incf sum x))))
but this uses
dolistandincfwhich are both in thecl-macspackage. Basically you can't escape theclpackage:oddpitself is aclfunction!My best effort using absolutely no
clfacilities 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.J.F. Sebastian : Thanks. I like variant w/ remove-if-not despite it is a CL (though works without #). What is the online reference for such functions, is it http://www.gnu.org/software/emacs/manual/elisp.html ?Gareth Rees : It's http://www.gnu.org/software/emacs/manual/cl.html — but if you have Emacs, you may already have the cl manual; try typing C-h i m cl RET.Gareth Rees : Common Lisp itself has a HyperSpec, which is online in various places, including here: http://www.lispworks.com/documentation/HyperSpec/Front/index.htm
0 comments:
Post a Comment