List version of reduce
[jscl.git] / src / sequence.lisp
index 8d2701b..789a7c3 100644 (file)
              (let ((,elt (aref ,nseq ,index)))
                ,@body))))))
 
              (let ((,elt (aref ,nseq ,index)))
                ,@body))))))
 
-(defun find (item seq &key key (test #'eql))
-  (if key
-      (do-sequence (x seq)
-        (when (funcall test (funcall key x) item)
-          (return x)))
-      (do-sequence (x seq)
-        (when (funcall test x item)
-          (return x)))))
+(defun find (item seq &key key (test #'eql testp) (test-not #'eql test-not-p))
+  (do-sequence (x seq)
+    (when (satisfies-test-p item x :key key :test test :testp testp
+                            :test-not test-not :test-not-p test-not-p)
+      (return x))))
 
 (defun find-if (predicate sequence &key key)
   (if key
 
 (defun find-if (predicate sequence &key key)
   (if key
         (when (funcall predicate x)
           (return x)))))
 
         (when (funcall predicate x)
           (return x)))))
 
-(defun position (elt sequence &key (test #'eql))
-  (do-sequence (x seq index)
-    (when (funcall test elt x)
-      (return index))))
+(defun position (elt sequence
+                 &key key (test #'eql testp)
+                   (test-not #'eql test-not-p)
+                   (start 0) end)
+  ;; TODO: Implement START and END efficiently for all the sequence
+  ;; functions.
+  (let ((end (or end (length sequence))))
+    (do-sequence (x sequence index)
+      (when (and (<= start index)
+                 (< index end)
+                 (satisfies-test-p elt x
+                                   :key key :test test :testp testp
+                                   :test-not test-not :test-not-p test-not-p))
+        (return index)))))
+
+;; TODO: need to support &key from-end
+(defun position-if (predicate sequence
+                 &key key (start 0) end)
+  ;; TODO: Implement START and END efficiently for all the sequence
+  ;; functions.
+  (let ((end (or end (length sequence))))
+    (do-sequence (x sequence index)
+      (when (and (<= start index)
+                 (< index end)
+                 (funcall predicate (if key (funcall key x) x)))
+        (return index)))))
 
 
-(defun remove (x seq)
+(defun position-if-not (predicate sequence
+                 &key key (start 0) end)
+  (position-if (complement predicate) sequence :key key :start start :end end))
+
+(defun remove (x seq &key key (test #'eql testp) (test-not #'eql test-not-p))
   (cond
     ((null seq)
      nil)
   (cond
     ((null seq)
      nil)
@@ -64,7 +87,8 @@
      (let* ((head (cons nil nil))
             (tail head))
        (do-sequence (elt seq)
      (let* ((head (cons nil nil))
             (tail head))
        (do-sequence (elt seq)
-         (unless (eql x elt)
+         (unless (satisfies-test-p x elt :key key :test test :testp testp
+                                   :test-not test-not :test-not-p test-not-p)
            (let ((new (list elt)))
              (rplacd tail new)
              (setq tail new))))
            (let ((new (list elt)))
              (rplacd tail new)
              (setq tail new))))
@@ -72,7 +96,8 @@
     (t
      (let (vector)
        (do-sequence (elt seq index)
     (t
      (let (vector)
        (do-sequence (elt seq index)
-         (if (eql x elt)
+         (if (satisfies-test-p x elt :key key :test test :testp testp
+                               :test-not test-not :test-not-p test-not-p)
              ;; Copy the beginning of the vector only when we find an element
              ;; that does not match.
              (unless vector
              ;; Copy the beginning of the vector only when we find an element
              ;; that does not match.
              (unless vector
      (if b
        (let ((diff (- b a)))
          (cond
      (if b
        (let ((diff (- b a)))
          (cond
-           ((zerop  diff) ()) 
+           ((zerop  diff) ())
            ((minusp diff)
             (error "Start index must be smaller than end index"))
            (t
            ((minusp diff)
             (error "Start index must be smaller than end index"))
            (t
                 (setq pointer (cdr pointer))
                 (when (null pointer)
                   (error "Ending index larger than length of list")))
                 (setq pointer (cdr pointer))
                 (when (null pointer)
                   (error "Ending index larger than length of list")))
-              (rplacd pointer ()) 
+              (rplacd pointer ())
               drop-a))))
        (copy-list (nthcdr a seq))))
               drop-a))))
        (copy-list (nthcdr a seq))))
-    ((arrayp seq) 
-     (if b
-       (slice seq a b)
-       (slice seq a)))
+    ((vectorp seq)
+     (let* ((b (or b (length seq)))
+            (size (- b a))
+            (new (make-array size :element-type (array-element-type seq))))
+       (do ((i 0 (1+ i))
+            (j a (1+ j)))
+           ((= j b) new)
+         (aset new i (aref seq j)))))
     (t (not-seq-error seq))))
     (t (not-seq-error seq))))
+
+(defun copy-seq (sequence)
+  (subseq sequence 0))
+
+;;; Based on the SBCL's reduce implementation
+(defun reduce (function sequence &key key from-end (start 0) end (initial-value nil ivp))
+  (let ((key (or key #'identity))
+        (end (or end (length sequence))))
+    (if (= end start)
+        (if ivp initial-value (funcall function))
+        (if from-end
+            (let ((sequence (nthcdr (- (length sequence) end) (reverse sequence))))
+              (do ((count (if ivp start (1+ start))
+                          (1+ count))
+                   (sequence (if ivp sequence (cdr sequence))
+                             (cdr sequence))
+                   (value (if ivp initial-value (funcall key (car sequence)))
+                          (funcall function (funcall key (car sequence)) value)))
+                  ((>= count end) value)))
+            (let ((sequence (nthcdr start sequence)))
+              (do ((count (if ivp start (1+ start))
+                          (1+ count))
+                   (sequence (if ivp sequence (cdr sequence))
+                             (cdr sequence))
+                   (value (if ivp initial-value (funcall key (car sequence)))
+                          (funcall function value (funcall key (car sequence)))))
+                  ((>= count end) value)))))))