Tree operations
Functions pretending lists are trees.
Function: -tree-seq (branch children tree)
Return a sequence of the nodes in tree, in depth-first search order.
branch is a predicate of one argument that returns non-nil if the passed argument is a branch, that is, a node that can have children.
children is a function of one argument that returns the children of the passed branch node.
Non-branch nodes are simply copied.
(-tree-seq 'listp 'identity '(1 (2 3) 4 (5 (6 7))))
⇒ ((1 (2 3) 4 (5 (6 7))) 1 (2 3) 2 3 4 (5 (6 7)) 5 (6 7) 6 7)(-tree-seq 'listp 'reverse '(1 (2 3) 4 (5 (6 7))))
⇒ ((1 (2 3) 4 (5 (6 7))) (5 (6 7)) (6 7) 7 6 5 4 (2 3) 3 2 1)(--tree-seq (vectorp it) (append it nil) [1 [2 3] 4 [5 [6 7]]])
⇒ ([1 [2 3] 4 [5 [6 7]]] 1 [2 3] 2 3 4 [5 [6 7]] 5 [6 7] 6 7)Function: -tree-map (fn tree)
Apply fn to each element of tree while preserving the tree structure.
(-tree-map '1+ '(1 (2 3) (4 (5 6) 7)))
⇒ (2 (3 4) (5 (6 7) 8))(-tree-map '(lambda (x) (cons x (expt 2 x))) '(1 (2 3) 4))
⇒ ((1 . 2) ((2 . 4) (3 . 8)) (4 . 16))(--tree-map (length it) '("<body>" ("<p>" "text" "</p>") "</body>"))
⇒ (6 (3 4 4) 7)Function: -tree-map-nodes (pred fun tree)
Call fun on each node of tree that satisfies pred.
If pred returns nil, continue descending down this node. If pred returns non-nil, apply fun to this node and do not descend further.
(-tree-map-nodes 'vectorp (lambda (x) (-sum (append x nil))) '(1 [2 3] 4 (5 [6 7] 8)))
⇒ (1 5 4 (5 13 8))(-tree-map-nodes 'keywordp (lambda (x) (symbol-name x)) '(1 :foo 4 ((5 6 :bar) :baz 8)))
⇒ (1 ":foo" 4 ((5 6 ":bar") ":baz" 8))(--tree-map-nodes (eq (car-safe it) 'add-mode) (-concat it (list :mode 'emacs-lisp-mode)) '(with-mode emacs-lisp-mode (foo bar) (add-mode a b) (baz (add-mode c d))))
⇒ (with-mode emacs-lisp-mode (foo bar) (add-mode a b :mode emacs-lisp-mode) (baz (add-mode c d :mode emacs-lisp-mode)))Function: -tree-reduce (fn tree)
Use fn to reduce elements of list tree. If elements of tree are lists themselves, apply the reduction recursively.
fn is first applied to first element of the list and second element, then on this result and third element from the list etc.
See -reduce-r (see -reduce-r) for how exactly are lists of zero or one element handled.
(-tree-reduce '+ '(1 (2 3) (4 5)))
⇒ 15(-tree-reduce 'concat '("strings" (" on" " various") ((" levels"))))
⇒ "strings on various levels"(--tree-reduce (cond ((stringp it) (concat it " " acc)) (t (let ((sn (symbol-name it))) (concat "<" sn ">" acc "</" sn ">")))) '(body (p "some words") (div "more" (b "bold") "words")))
⇒ "<body><p>some words</p> <div>more <b>bold</b> words</div></body>"Function: -tree-reduce-from (fn init-value tree)
Use fn to reduce elements of list tree. If elements of tree are lists themselves, apply the reduction recursively.
fn is first applied to init-value and first element of the list, then on this result and second element from the list etc.
The initial value is ignored on cons pairs as they always contain two elements.
(-tree-reduce-from '+ 1 '(1 (1 1) ((1))))
⇒ 8(--tree-reduce-from (-concat acc (list it)) nil '(1 (2 3 (4 5)) (6 7)))
⇒ ((7 6) ((5 4) 3 2) 1)Function: -tree-mapreduce (fn folder tree)
Apply fn to each element of tree, and make a list of the results. If elements of tree are lists themselves, apply fn recursively to elements of these nested lists.
Then reduce the resulting lists using folder and initial value init-value. See -reduce-r-from (see -reduce-r-from).
This is the same as calling -tree-reduce (see -tree-reduce) after -tree-map (see -tree-map) but is twice as fast as it only traverse the structure once.
(-tree-mapreduce 'list 'append '(1 (2 (3 4) (5 6)) (7 (8 9))))
⇒ (1 2 3 4 5 6 7 8 9)(--tree-mapreduce 1 (+ it acc) '(1 (2 (4 9) (2 1)) (7 (4 3))))
⇒ 9(--tree-mapreduce 0 (max acc (1+ it)) '(1 (2 (4 9) (2 1)) (7 (4 3))))
⇒ 3Function: -tree-mapreduce-from (fn folder init-value tree)
Apply fn to each element of tree, and make a list of the results. If elements of tree are lists themselves, apply fn recursively to elements of these nested lists.
Then reduce the resulting lists using folder and initial value init-value. See -reduce-r-from (see -reduce-r-from).
This is the same as calling -tree-reduce-from (see -tree-reduce-from) after -tree-map (see -tree-map) but is twice as fast as it only traverse the structure once.
(-tree-mapreduce-from 'identity '* 1 '(1 (2 (3 4) (5 6)) (7 (8 9))))
⇒ 362880(--tree-mapreduce-from (+ it it) (cons it acc) nil '(1 (2 (4 9) (2 1)) (7 (4 3))))
⇒ (2 (4 (8 18) (4 2)) (14 (8 6)))(concat "{" (--tree-mapreduce-from (cond ((-cons-pair? it) (concat (symbol-name (car it)) " -> " (symbol-name (cdr it)))) (t (concat (symbol-name it) " : {"))) (concat it (unless (or (equal acc "}") (equal (substring it (1- (length it))) "{")) ", ") acc) "}" '((elisp-mode (foo (bar . booze)) (baz . qux)) (c-mode (foo . bla) (bum . bam)))))
⇒ "{elisp-mode : {foo : {bar -> booze}, baz -> qux}, c-mode : {foo -> bla, bum -> bam}}"Function: -clone (list)
Create a deep copy of list. The new list has the same elements and structure but all cons are replaced with new ones. This is useful when you need to clone a structure such as plist or alist.
(let* ((a (list (list 1))) (b (-clone a))) (setcar (car a) 2) b)
⇒ ((1))