From 9410f7e5a60e4c1aea69e38d78a7ad5710b3707d Mon Sep 17 00:00:00 2001 From: Magnar Sveen Date: Sun, 21 Oct 2012 16:53:37 +0200 Subject: [PATCH] Add !replace-where --- README.md | 13 +++++++++++++ bang.el | 20 ++++++++++++++++++++ examples.el | 5 +++++ 3 files changed, 38 insertions(+) diff --git a/README.md b/README.md index f488889..8cbfadd 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ Or you can just dump `bang.el` in your load path somewhere. * [!concat](#concat-rest-lists) `(&rest lists)` * [!mapcat](#mapcat-fn-list) `(fn list)` * [!interpose](#interpose-sep-list) `(sep list)` +* [!replace-where](#replace-where-pred-rep-list) `(pred rep list)` * [!first](#first-fn-list) `(fn list)` * [!partial](#partial-fn-rest-args) `(fn &rest args)` * [!rpartial](#rpartial-fn-rest-args) `(fn &rest args)` @@ -170,6 +171,18 @@ Returns a new list of all elements in `list` separated by `sep`. (!interpose "-" '("a" "b" "c")) ;; => '("a" "-" "b" "-" "c") ``` +### !replace-where `(pred rep list)` + +Returns a new list where the elements in `list` that does not match the `pred` function +are unchanged, and where the elements in `list` that do match the `pred` function are mapped +through the `rep` function. + +```cl +(!replace-where 'even? 'square '(1 2 3 4)) ;; => '(1 4 3 16) +(!replace-where (lambda (n) (= n 3)) (lambda (n) 0) '(1 2 3 4)) ;; => '(1 2 0 4) +(!!replace-where (> it 2) (* it it) '(1 2 3 4)) ;; => '(1 2 9 16) +``` + ### !first `(fn list)` Returns the first x in `list` where (`fn` x) is non-nil, else nil. diff --git a/bang.el b/bang.el index 78c21a5..065662d 100644 --- a/bang.el +++ b/bang.el @@ -155,6 +155,26 @@ Thus function FN should return a collection." (setq list (cdr list))) (nreverse result))) +(defmacro !!replace-where (pred rep list) + "Returns a new list where the elements in LIST that does not match the PRED function +are unchanged, and where the elements in LIST that do match the PRED function are mapped +through the REP function." + (let ((l (make-symbol "list")) + (r (make-symbol "result"))) + `(let ((,l ,list) + (,r '())) + (while ,l + (let ((it (car ,l))) + (setq ,r (cons (if ,pred ,rep it) ,r))) + (setq ,l (cdr ,l))) + (nreverse ,r)))) + +(defun !replace-where (pred rep list) + "Returns a new list where the elements in LIST that does not match the PRED function +are unchanged, and where the elements in LIST that do match the PRED function are mapped +through the REP function." + (!!replace-where (funcall pred it) (funcall rep it) list)) + (defun !partial (fn &rest args) "Takes a function FN and fewer than the normal arguments to FN, and returns a fn that takes a variable number of additional ARGS. diff --git a/examples.el b/examples.el index 970953d..6bfec6f 100644 --- a/examples.el +++ b/examples.el @@ -63,6 +63,11 @@ (!interpose "-" '("a")) => '("a") (!interpose "-" '("a" "b" "c")) => '("a" "-" "b" "-" "c")) +(defexamples !replace-where + (!replace-where 'even? 'square '(1 2 3 4)) => '(1 4 3 16) + (!replace-where (lambda (n) (= n 3)) (lambda (n) 0) '(1 2 3 4)) => '(1 2 0 4) + (!!replace-where (> it 2) (* it it) '(1 2 3 4)) => '(1 2 9 16)) + (defexamples !first (!first 'even? '(1 2 3)) => 2 (!first 'even? '(1 3 5)) => nil