[alexandria.git] updated branch master: 3448822 add EXTREMUM

Nikodemus Siivola nsiivola at common-lisp.net
Wed Apr 25 12:29:02 UTC 2012


The branch master has been updated:
       via  34488223ff5b7eb19d73075481c91f829af5d6bd (commit)
      from  daa087258b7edd0fa2c31d2e4583c2dc8380a143 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 34488223ff5b7eb19d73075481c91f829af5d6bd
Author: Nikodemus Siivola <nikodemus at random-state.net>
Date:   Wed Apr 25 15:24:49 2012 +0300

    add EXTREMUM
    
      From http://www.cliki.net/EXTREMUM
    
      A simple version built on top of REDUCE for now.

-----------------------------------------------------------------------

Summary of changes:
 package.lisp   |    4 +++-
 sequences.lisp |   51 +++++++++++++++++++++++++++++++++++++++++++++++++++
 tests.lisp     |   28 ++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletions(-)

diff --git a/package.lisp b/package.lisp
index 673ed30..babeb95 100644
--- a/package.lisp
+++ b/package.lisp
@@ -107,17 +107,19 @@
    #:emptyp
    #:ends-with
    #:ends-with-subseq
+   #:extremum
    #:first-elt
    #:last-elt
+   #:length=
    #:map-combinations
    #:map-derangements
    #:map-permutations
+   #:no-extremum
    #:proper-sequence
    #:random-elt
    #:removef
    #:rotate
    #:sequence-of-length-p
-   #:length=
    #:shuffle
    #:starts-with
    #:starts-with-subseq
diff --git a/sequences.lisp b/sequences.lisp
index 9e4ff74..cb01081 100644
--- a/sequences.lisp
+++ b/sequences.lisp
@@ -484,3 +484,54 @@ if calling FUNCTION modifies either the derangement or SEQUENCE."
       sequence)))
 
 (declaim (notinline sequence-of-length-p))
+
+(define-condition no-extremum (error)
+  ()
+  (:report (lambda (condition stream)
+             (declare (ignore condition))
+             (format stream "Empty sequence in ~S." 'extremum))))
+
+
+(defun extremum (sequence predicate &key key (start 0) end)
+  "Returns the element of SEQUENCE that would appear first if the subsequence
+bounded by START and END was sorted using PREDICATE and KEY.
+
+EXTREMUM determines the relationship between two elements of SEQUENCE by using
+the PREDICATE function. PREDICATE should return true if and only if the first
+argument is strictly less than the second one (in some appropriate sense). Two
+arguments X and Y are considered to be equal if (FUNCALL PREDICATE X Y)
+and (FUNCALL PREDICATE Y X) are both false.
+
+The arguments to the PREDICATE function are computed from elements of SEQUENCE
+using the KEY function, if supplied. If KEY is not supplied or is NIL, the
+sequence element itself is used.
+
+If SEQUENCE is empty, then the error NO-EXTREMUM is signalled. Invoking the
+CONTINUE restart will cause extremum to return NIL."
+  (let* ((pred-fun (ensure-function predicate))
+         (key-fun (unless (or (not key) (eq key 'identity) (eq key #'identity))
+                    (ensure-function key)))
+         (real-end (or end (length sequence))))
+    (cond ((> real-end start)
+           (if key-fun
+               (flet ((reduce-keys (a b)
+                        (if (funcall pred-fun
+                                     (funcall key-fun a)
+                                     (funcall key-fun b))
+                            a
+                            b)))
+                 (declare (dynamic-extent #'reduce-keys))
+                 (reduce #'reduce-keys sequence :start start :end real-end))
+               (flet ((reduce-elts (a b)
+                        (if (funcall pred-fun a b)
+                            a
+                            b)))
+                 (declare (dynamic-extent #'reduce-elts))
+                 (reduce #'reduce-elts sequence :start start :end real-end))))
+          ((= real-end start)
+           (cerror "Return NIL instead." 'no-extremum))
+          (t
+           (error "Invalid bounding indexes for sequence of length ~S: ~S ~S, ~S ~S"
+                  (length sequence)
+                  :start start
+                  :end end)))))
diff --git a/tests.lisp b/tests.lisp
index d104bda..e218113 100644
--- a/tests.lisp
+++ b/tests.lisp
@@ -1828,3 +1828,31 @@
   t
   t
   t)
+
+(deftest extremum.1
+    (let ((n 0))
+      (dotimes (i 10)
+       (let ((data (shuffle (coerce (iota 10000 :start i) 'vector)))
+             (ok t))
+         (unless (eql i (extremum data #'<))
+           (setf ok nil))
+         (unless (eql i (extremum (coerce data 'list) #'<))
+           (setf ok nil))
+         (unless (eql (+ 9999 i) (extremum data #'>))
+           (setf ok nil))
+         (unless (eql (+ 9999 i) (extremum (coerce  data 'list) #'>))
+           (setf ok nil))
+         (when ok
+           (incf n))))
+      (when (eql 10 (extremum #(100 1 10 1000) #'> :start 1 :end 3))
+        (incf n))
+      (when (eql -1000 (extremum #(100 1 10 -1000) #'> :key 'abs))
+        (incf n))
+      (let ((err nil))
+        (handler-bind ((no-extremum (lambda (c)
+                                      (setf err c)
+                                      (continue c))))
+          (when (eq nil (extremum "" #'error))
+            (when err
+              (incf n))))))
+  13)
-- 
Alexandria hooks/post-receive




More information about the alexandria-cvs mailing list