4d881c990060

`take-while` and `drop-while`
[view raw] [browse files]
author Steve Losh <steve@stevelosh.com>
date Wed, 01 Mar 2017 19:14:51 +0000
parents 2746fc7667d9
children c49425b33f17
branches/tags (none)
files DOCUMENTATION.markdown losh.lisp package.lisp

Changes

--- 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.
--- 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`.
 
--- 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