Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Emacs Lisp: How to sum odd numbers in a list?

Tags:

emacs

elisp

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:

How to sum a list of numbers in Emacs Lisp?

like image 528
jfs Avatar asked Feb 26 '09 16:02

jfs


3 Answers

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.

like image 65
Gareth Rees Avatar answered Sep 28 '22 06:09

Gareth Rees



(apply '+ (delq nil (mapcar (lambda (x) (and (= 1 (% x 2)) x)) '(1 2 3 4 5))))
like image 28
rzab Avatar answered Sep 28 '22 04:09

rzab


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.

like image 42
Mirzhan Irkegulov Avatar answered Sep 28 '22 06:09

Mirzhan Irkegulov