Elisp: Sequence Iteration
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
(aliasseq-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"