Elisp: Sequence Iteration

By Xah Lee. Date: . Last updated: .

Map a Function to Sequence

mapcar

(mapcar FUNCTION SEQUENCE)

  • Apply function to each element of Sequence
  • Return the result as a list.
  • FUNCTION must be a Symbol, or Lambda.
;; apply a lambda to each vector (take 1st element)
(mapcar (lambda (x) (aref x 0)) [[1 2] [3 4] [5 6]])
;; (1 3 5)

;; apply a buildin function named 1+ to each vector element
(mapcar '1+ [0 1 2])
;; (1 2 3)

;; apply a function to list
(mapcar '1+ '(0 1 2))
;; (1 2 3)
seq-map

same as mapcar

seq-mapn
  • Apply a function of n params over n sequences, taking one arg from each.
  • return a list.
(seq-mapn
 (lambda (x y) (+ x y))
 (vector 1 2 3)
 (vector 4 5 6))
;; (5 7 9)

Insert / Delete / Modify Items (At Arbitrary Positions)

seq-mapcat

(seq-mapcat FUNCTION SEQUENCE &optional TYPE)

Apply a function that return a list (can be empty list), but insert its elements into the sequence.

  • if the function return a empty list (nil), the item at the position is removed.
  • if the function return a list of single item, the item at the position is replaced.
  • if the function return a non-empty list, the items are insert at the position.

💡 TIP: This function is more general than map because map cannot delete items, and more general than filter because filter cannot add item nor transform the items you want.

(setq xx (vector "aa" "bb" "m,n" "cc" ))

;; if the string contains a comma, split it into 2 items

(seq-mapcat
 (lambda (x)
   (if (string-match "," x)
       (split-string x ",")
     (list x)))
 xx)
;; ("aa" "bb" "m" "n" "cc")

Transform then Filter

seq-keep

(seq-keep FUNCTION SEQUENCE)

apply a function, return a list of all function's results that's not nil.

this is like transform and filter in one.

(setq xx (vector 1 2 3 4 5 6))

;; get all even elements, convert to string, prepend x
(seq-keep
 (lambda (x)
   (if (eq (mod x 2) 0)
       (format "x%s" x)
     nil))
 xx)
;; ("x2" "x4" "x6")

Foreach on Sequence (side-effect use)

mapc

(mapc FUNCTION SEQUENCE)

  • Apply function to each element of Sequence
  • Return SEQUENCE unchanged.
(mapc
 (lambda (x)
   (insert (number-to-string x)))
 (number-sequence 1 9))

;; insert 123456789
;; apply a file function to a list of files
(mapc 'my-update-footer
      (list "~/x1.html" "~/x2.html" "~/x3.html"))
seq-do (alias seq-each)

Loop a function over the sequence. (Same as mapc)

seq-doseq

(seq-doseq (VAR SEQUENCE) BODY)

loop a variable over the sequence. (similar to dolist.)

(setq xx [1 2 3] )
(seq-doseq (x xx)
  (message "x is %s" x))
;; return the original sequence [1 2 3]

Foreach with Break

These are useful as functional form of loop with break. As soon as a condition found, the loop stops.

seq-some

Apply a function to all, return true if at least one result is true. As soon as a value is true, the loop stops.

;; demo of seq-some
(seq-some (lambda (x) (eq 5 x)) [4 5 6])
;; t
seq-every-p

Apply a function to all, return true if every result is true. As soon as a value is false, the loop stops.

Reduce (Fold, Accumulator)

Reduce is a general way to do loop in functional programing style. A function is feed args from a list, and each time, the result is feed back to the function.

It solves the problem of storing value in a global variable or keeping state, such as a increment counter. By passing the state to the function.

seq-reduce

(seq-reduce FUNCTION SEQUENCE INITIAL-VALUE)

Recurse a function of 2 parameters x y, each time feed x the last result, feed y the new item in sequence, till no more items. Return the result.

start with putting INITIAL-VALUE in x.

For example:

  • (seq-reduce f [1] 0) → (f 0 1)
  • (seq-reduce f [1 2] 0) → (f (f 0 1) 2)
  • (seq-reduce f [1 2 3] 0) → (f (f (f 0 1) 2) 3)
(setq xx (vector "a" "b" "c"))

(seq-reduce
 (lambda (x y) (concat x y))
 xx
 "")
;; "abc"
(setq xx (vector "a" "b" "c"))

(seq-reduce
 (lambda (x y) (concat x y))
 (seq-drop xx 1)
 (seq-first xx))

;; "abc"

Elisp, Loop and Iteration

Elisp, sequence functions

Elisp, Vector