Implement REMOVE-IF[-NOT] for vectors
authorOwen Rodley <Strigoides@gmail.com>
Thu, 9 May 2013 02:51:33 +0000 (14:51 +1200)
committerOwen Rodley <Strigoides@gmail.com>
Thu, 9 May 2013 02:57:19 +0000 (14:57 +1200)
src/sequence.lisp
tests/seq.lisp

index 93e3fdd..738995f 100644 (file)
       (return-from every nil)))
   t)
 
-
-;;; TODO: Support both List and vectors in the following functions
-
-(defun remove-if (func list)
+(defun remove-if (func seq)
   (cond
-    ((null list)
-     nil)
-    ((funcall func (car list))
-     (remove-if func (cdr list)))
-    (t
-     ;;
-     (cons (car list) (remove-if func (cdr list))))))
+    ((listp  seq) (list-remove-if   func seq nil))
+    ((arrayp seq) (vector-remove-if func seq nil))
+    (t (error "`~S' is not of type SEQUENCE" seq))))
 
-(defun remove-if-not (func list)
+(defun remove-if-not (func seq)
   (cond
-    ((null list)
-     nil)
-    ((funcall func (car list))
-     (cons (car list) (remove-if-not func (cdr list))))
-    (t
-     (remove-if-not func (cdr list)))))
+    ((listp  seq) (list-remove-if   func seq t))
+    ((arrayp seq) (vector-remove-if func seq t))
+    (t (error "`~S' is not of type SEQUENCE" seq))))
+
+(defun list-remove-if (func list negate)
+  (if (endp list)
+    ()
+    (let ((test (funcall func (car list))))
+      (if (if negate (not test) test)
+        (list-remove-if func (cdr list) negate)
+        (cons (car list) (list-remove-if func (cdr list) negate))))))
+
+(defun vector-remove-if (func vector negate)
+  (let ((out-vector (make-array 0)))
+    (dotimes (i (length vector))
+      (let* ((element (aref vector i))
+             (test (funcall func element)))
+        (when (if negate test (not test))
+          (vector-push-extend element out-vector))))
+    out-vector))
+
+;;; TODO: Support both List and vectors in the following functions
 
 (defun subseq (seq a &optional b)
   (if b
       (slice seq a b)
       (slice seq a)))
-
index 326b4f7..c117831 100644 (file)
@@ -5,3 +5,11 @@
 (test (find 1 (list 2 1 3)))
 (test (not (find 1 (list 2 2 2))))
 (test (not (find 1 (remove 1 (list 1 2 3 1)))))
+
+(test (equal (remove-if     #'zerop '(1 0 2 0 3)) '(1 2 3)))
+(test (equal (remove-if-not #'zerop '(1 0 2 0 3)) '(0 0)))
+
+;; TODO: Rewrite these tests when EQUALP exists and works on vectors
+(let ((v1 (remove-if #'zerop #(1 0 2 0 3))))
+  (test (and (= (aref v1 0) 1) (= (aref v1 1) 2) (= (aref v1 2) 3)))) 
+(test (every #'zerop (remove-if-not #'zerop #(1 0 2 0 3))))