emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Enhance seq-min and seq-max


From: Michael Heerdegen
Subject: Re: Enhance seq-min and seq-max
Date: Sun, 16 Jun 2019 01:46:38 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux)

Michael Heerdegen <address@hidden> writes:

> Like this, maybe?

Here is an update.  I improved the documentation and optimized the code
to avoid repeated calls of the KEY function on the same element.  There
are now more cases, but the code should be more efficient.

If this is accepted, I will care about the update of the manual.

From 8c870d37e9f6c67f6eb1566cb1307465675b4d8a Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <address@hidden>
Date: Fri, 10 May 2019 15:08:57 +0200
Subject: [PATCH] WIP: Enhance seq-min and seq-max

---
 lisp/emacs-lisp/seq.el | 62 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 55 insertions(+), 7 deletions(-)

diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index 3413cd1513..b681adb393 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -451,15 +451,63 @@ seq-group-by
    (seq-reverse sequence)
    nil))

-(cl-defgeneric seq-min (sequence)
+(cl-defgeneric seq-min (sequence &optional predicate key)
   "Return the smallest element of SEQUENCE.
-SEQUENCE must be a sequence of numbers or markers."
-  (apply #'min (seq-into sequence 'list)))
-
-(cl-defgeneric seq-max (sequence)
+With PREDICATE given, use it to compare elements.
+With function KEY given, call it with the individual elements as
+arguments and compare the results instead of the elements.
+
+PREDICATE doesn't need to define a total order.  The return value is
+always the first element X of SEQUENCE so that for no following Y
+
+  (funcall PREDICATE (funcall KEY Y) (funcall KEY X))
+
+yields non-nil, where PREDICATE defaults to #'< and KEY to
+#'identity."
+  (if predicate
+      (if key
+          (let ((first (car sequence)))
+            (cdr (seq-reduce
+                  (lambda (key-x-and-x y)
+                    (let ((key-y-and-y (cons (funcall key y) y)))
+                      (if (funcall predicate (car key-y-and-y) (car 
key-x-and-x))
+                          key-y-and-y
+                        key-x-and-x)))
+                  (cdr sequence)
+                  (cons (funcall key first) first))))
+        (seq-reduce
+         (lambda (x y) (if (funcall predicate y x) y x))
+         (cdr sequence) (car sequence)))
+    (apply #'min (seq-into sequence 'list))))
+
+(cl-defgeneric seq-max (sequence &optional predicate key)
   "Return the largest element of SEQUENCE.
-SEQUENCE must be a sequence of numbers or markers."
-  (apply #'max (seq-into sequence 'list)))
+With PREDICATE given, use it to compare elements.
+With function KEY given, call it with the individual elements as
+arguments and compare the results instead of the elements.
+
+PREDICATE doesn't need to define a total order.  The return value is
+always the first element X of SEQUENCE so that for no following Y
+
+  (funcall PREDICATE (funcall KEY X) (funcall KEY Y))
+
+yields non-nil, where PREDICATE defaults to #'< and KEY to
+#'identity."
+  (if predicate
+      (if key
+          (let ((first (car sequence)))
+            (cdr (seq-reduce
+                  (lambda (key-x-and-x y)
+                    (let ((key-y-and-y (cons (funcall key y) y)))
+                      (if (funcall predicate (car key-x-and-x) (car 
key-y-and-y))
+                          key-y-and-y
+                        key-x-and-x)))
+                  (cdr sequence)
+                  (cons (funcall key first) first))))
+        (seq-reduce
+         (lambda (x y) (if (funcall predicate x y) y x))
+         (cdr sequence) (car sequence)))
+    (apply #'max (seq-into sequence 'list))))

 (defun seq--count-successive (pred sequence)
   "Return the number of successive elements for which (PRED element) is 
non-nil in SEQUENCE."
--
2.20.1


Thanks,

Michael.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]