diff --git a/README.md b/README.md index 534edaa..fe383ae 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,8 @@ Include this in your emacs settings to get syntax highlighting: * [-map-when](#-map-when-pred-rep-list) `(pred rep list)` * [-replace](#-replace-old-new-list) `(old new list)` * [-map-indexed](#-map-indexed-fn-list) `(fn list)` +* [-splice](#-splice-pred-fun-list) `(pred fun list)` +* [-splice-list](#-splice-list-pred-new-list-list) `(pred new-list list)` * [-flatten](#-flatten-l) `(l)` * [-flatten-n](#-flatten-n-num-list) `(num list)` * [-concat](#-concat-rest-lists) `(&rest lists)` @@ -309,6 +311,33 @@ In the anaphoric form `--map-indexed`, the index is exposed as `it-index`. (--map-indexed (- it it-index) '(1 2 3 4)) ;; => '(1 1 1 1) ``` +#### -splice `(pred fun list)` + +Splice lists generated by `fun` in place of elements matching `pred` in `list`. + +`fun` takes the element matching `pred` as input. + +This function can be used as replacement for `,@` in case you +need to splice several lists at marked positions (for example +with keywords). + +```cl +(-splice 'even? (lambda (x) (list x x)) '(1 2 3 4)) ;; => '(1 2 2 3 4 4) +(--splice 't (list it it) '(1 2 3 4)) ;; => '(1 1 2 2 3 3 4 4) +(--splice (equal it :magic) '((list of) (magical) (code)) '((foo) (bar) :magic (baz))) ;; => '((foo) (bar) (list of) (magical) (code) (baz)) +``` + +#### -splice-list `(pred new-list list)` + +Splice `new-list` in place of elements matching `pred` in `list`. + +See also more general version: `-splice`. + +```cl +(-splice-list 'keywordp '(a b c) '(1 :foo 2)) ;; => '(1 a b c 2) +(-splice-list 'keywordp nil '(1 :foo 2)) ;; => '(1 2) +``` + #### -flatten `(l)` Takes a nested list `l` and returns its contents as a single, flat list. diff --git a/dash.el b/dash.el index d987ef8..775e799 100644 --- a/dash.el +++ b/dash.el @@ -301,6 +301,36 @@ Elements are compared using `equal'." Thus function FN should return a list." (--mapcat (funcall fn it) list)) +(defun -splice (pred fun list) + "Splice lists generated by FUN in place of elements matching PRED in LIST. + +FUN takes the element matching PRED as input. + +This function can be used as replacement for `,@' in case you +need to splice several lists at marked positions (for example +with keywords)." + (let (r) + (--each list + (if (funcall pred it) + (let ((new (funcall fun it))) + (--each new (!cons it r))) + (!cons it r))) + (nreverse r))) + +(defmacro --splice (pred form list) + "Anaphoric form of `-splice'." + `(-splice (lambda (it) ,pred) (lambda (it) ,form) ,list)) + +(defun -splice-list (pred new-list list) + "Splice NEW-LIST in place of elements matching PRED in LIST. + +See also more general version: `-splice'." + (-splice pred (lambda (_) new-list) list)) + +(defun --splice-list (pred new-list list) + "Anaphoric form of `-splice-list'." + `(-splice-list (lambda (it) ,pred) ,new-list ,list)) + (defun -cons* (&rest args) "Makes a new list from the elements of ARGS. @@ -1471,6 +1501,10 @@ structure such as plist or alist." "--keep" "-map-indexed" "--map-indexed" + "-splice" + "--splice" + "-splice-list" + "--splice-list" "-map-when" "--map-when" "-replace-where" diff --git a/dev/examples.el b/dev/examples.el index 2f71f99..23697c2 100644 --- a/dev/examples.el +++ b/dev/examples.el @@ -48,6 +48,15 @@ (-map-indexed (lambda (index item) (- item index)) '(1 2 3 4)) => '(1 1 1 1) (--map-indexed (- it it-index) '(1 2 3 4)) => '(1 1 1 1)) + (defexamples -splice + (-splice 'even? (lambda (x) (list x x)) '(1 2 3 4)) => '(1 2 2 3 4 4) + (--splice 't (list it it) '(1 2 3 4)) => '(1 1 2 2 3 3 4 4) + (--splice (equal it :magic) '((list of) (magical) (code)) '((foo) (bar) :magic (baz))) => '((foo) (bar) (list of) (magical) (code) (baz))) + + (defexamples -splice-list + (-splice-list 'keywordp '(a b c) '(1 :foo 2)) => '(1 a b c 2) + (-splice-list 'keywordp nil '(1 :foo 2)) => '(1 2)) + (defexamples -flatten (-flatten '((1))) => '(1) (-flatten '((1 (2 3) (((4 (5))))))) => '(1 2 3 4 5)