# HG changeset patch # User Steve Losh # Date 1488395691 0 # Node ID 4d881c9900609dcc96939f87c3530801d99e41c5 # Parent 2746fc7667d9e49f74bc7752fa5c8d47955c42f6 `take-while` and `drop-while` diff -r 2746fc7667d9 -r 4d881c990060 DOCUMENTATION.markdown --- a/DOCUMENTATION.markdown Mon Feb 27 13:52:44 2017 +0000 +++ b/DOCUMENTATION.markdown Wed Mar 01 19:14:51 2017 +0000 @@ -306,7 +306,7 @@ &BODY BODY) -Run `body` to gather some things and return them. +Run `body` to gather some things and return a fresh list of them. `body` will be executed with the symbol `gather` bound to a function of one argument. Once `body` has finished, a list of everything `gather` was called @@ -335,6 +335,42 @@ +### `GATHERING-VECTOR` (macro) + + (GATHERING-VECTOR OPTIONS + &BODY + BODY) + +Run `body` to gather some things and return a fresh vector of them. + + `body` will be executed with the symbol `gather` bound to a function of one + argument. Once `body` has finished, a vector of everything `gather` was + called on will be returned. This vector will be adjustable and have a fill + pointer. + + It's handy for pulling results out of code that executes procedurally and + doesn't return anything, like `maphash` or Alexandria's `map-permutations`. + + The `gather` function can be passed to other functions, but should not be + retained once the `gathering` form has returned (it would be useless to do so + anyway). + + Examples: + + (gathering-vector () + (dotimes (i 5) + (gather i)) + => + #(0 1 2 3 4) + + (gathering-vector () + (mapc #'gather '(1 2 3)) + (mapc #'gather '(a b))) + => + #(1 2 3 a b) + + + ### `IF-FOUND` (macro) (IF-FOUND VAR LOOKUP-EXPR THEN ELSE) @@ -608,6 +644,14 @@ +### `PROFILE` (macro) + + (PROFILE + &BODY + BODY) + +Profile `body` and dump the report to `lisp.prof`. + ### `SHUT-UP` (macro) (SHUT-UP @@ -1463,6 +1507,24 @@ +### `DROP-WHILE` (function) + + (DROP-WHILE PREDICATE SEQ) + +Drop elements from `seq` as long as `predicate` remains true. + + The result will be a fresh sequence of the same type as `seq`. + + Example: + + (drop-while #'evenp '(2 4 5 6 7 8)) + ; => (5 6 7 8) + + (drop-while #'evenp #(2)) + ; => #(2) + + + ### `ENUMERATE` (function) (ENUMERATE SEQUENCE &KEY (START 0) (STEP 1) KEY) @@ -1609,6 +1671,24 @@ +### `TAKE-WHILE` (function) + + (TAKE-WHILE PREDICATE SEQ) + +Take elements from `seq` as long as `predicate` remains true. + + The result will be a fresh sequence of the same type as `seq`. + + Example: + + (take-while #'evenp '(2 4 5 6 7 8)) + ; => (2 4) + + (take-while #'evenp #(1)) + ; => #() + + + ## Package `LOSH.WEIGHTLISTS` A simple data structure for choosing random items with weighted probabilities. diff -r 2746fc7667d9 -r 4d881c990060 losh.lisp --- a/losh.lisp Mon Feb 27 13:52:44 2017 +0000 +++ b/losh.lisp Wed Mar 01 19:14:51 2017 +0000 @@ -1727,6 +1727,33 @@ (sequence (take-seq n seq)))) +(defun-inline take-while-list (predicate list) + (iterate (for item :in list) + (while (funcall predicate item)) + (collect item))) + +(defun-inline take-while-seq (predicate seq) + (subseq seq 0 (position-if-not predicate seq))) + +(defun take-while (predicate seq) + "Take elements from `seq` as long as `predicate` remains true. + + The result will be a fresh sequence of the same type as `seq`. + + Example: + + (take-while #'evenp '(2 4 5 6 7 8)) + ; => (2 4) + + (take-while #'evenp #(1)) + ; => #() + + " + (ctypecase seq + (list (take-while-list predicate seq)) + (sequence (take-while-seq predicate seq)))) + + (defun-inline drop-list (n list) (copy-list (nthcdr n list))) @@ -1757,6 +1784,36 @@ (sequence (drop-seq n seq)))) +(defun-inline drop-while-list (predicate list) + (iterate (for tail :on list) + (while (funcall predicate (first tail))) + (finally (return (copy-list tail))))) + +(defun-inline drop-while-seq (predicate seq) + (let ((start (position-if-not predicate seq))) + (if start + (subseq seq start) + (subseq seq 0 0)))) + +(defun drop-while (predicate seq) + "Drop elements from `seq` as long as `predicate` remains true. + + The result will be a fresh sequence of the same type as `seq`. + + Example: + + (drop-while #'evenp '(2 4 5 6 7 8)) + ; => (5 6 7 8) + + (drop-while #'evenp #(2)) + ; => #(2) + + " + (ctypecase seq + (list (drop-while-list predicate seq)) + (sequence (drop-while-seq predicate seq)))) + + (defun extrema (predicate sequence) "Return the smallest and largest elements of `sequence` according to `predicate`. diff -r 2746fc7667d9 -r 4d881c990060 package.lisp --- a/package.lisp Mon Feb 27 13:52:44 2017 +0000 +++ b/package.lisp Wed Mar 01 19:14:51 2017 +0000 @@ -268,7 +268,9 @@ :proportions :group-by :take - :drop)) + :take-while + :drop + :drop-while)) (defpackage :losh.weightlists (:documentation