bug#81581: [PATCH 1/1] Add a LESSP argument to 'seq-min' and 'seq-max'
Philip Kaludercic <[email protected]>
| Newsgroups | gmane.emacs.bugs |
|---|---|
| Message-ID | <[email protected]> |
Sean Whitton <[email protected]> writes: > Philip Kaludercic [14/Aug 4:07pm GMT] wrote: >> Sean Whitton <[email protected]> writes: >> >>> Philip Kaludercic [09/Aug 4:29pm GMT] wrote: >>>>> Code looks good, interesting approach with the eval-when-compile >>>>> (I would have used a cl-loop since it doesn't seem like it's truly a >>>>> reduction, but what you have is fine). >>>> >>>> Why isn't this a reduction? >>> >>> Just a defeasible aesthetic intuition. >> >> My counter-argument is that min is a associative operation, and given a >> non-empty list kind-of unital as well, so for me it fits the bill. >> >>>> Sean Whitton <[email protected]> writes: >>>> >>>>> Sean Whitton [09/Aug 11:50am +01] wrote: >>>>>> Code looks good, interesting approach with the eval-when-compile >>>>>> (I would have used a cl-loop since it doesn't seem like it's truly a >>>>>> reduction, but what you have is fine). >>>>> >>>>> Well, a while loop, probably, given seq.el is preloaded. >>>> >>>> Hmm, but that would amount to just manually looping over the sequence >>>> (seq-length seq) many times and comparing the current best element with >>>> that in (seq-elt seq i)? >>> >>> Yes. >> >> I would vote against this, since when reducing over a list this would >> require a O(n) access for every element of the list (O(n) again), while >> seq-reduce, via seq-do calls mapc internally, that iterates over the >> list directly. > > That's fine, I was just making a few comments. > > Using a keyword argument, though, I do think you should change. Sure, I've made that change add added a :key keyword while at it. Also note there was a bug in the last version, where if the sequence is empty it would return a symbol instead of raising an error:
0001-Add-a-LESSP-argument-to-seq-min-and-seq-max.patch
(text/x-diff, 3 KB)
From 83d10a35ce274a5a10c3d925956923307589ac7e Mon Sep 17 00:00:00 2001 From: Philip Kaludercic <[email protected]> Date: Sat, 8 Aug 2026 21:56:57 +0200 Subject: [PATCH] Add a LESSP argument to 'seq-min' and 'seq-max' * lisp/emacs-lisp/seq.el (seq-min, seq-max): Add an optional argument allowing the generalization of sequence to more than just numerical data. --- lisp/emacs-lisp/seq.el | 44 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index b8f35c10def..b541adca003 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el @@ -604,16 +604,48 @@ seq-group-by (seq-reverse sequence) nil)) -(cl-defgeneric seq-min (sequence) +(cl-defgeneric seq-min (sequence &key (key #'identity) (lessp #'value<)) "Return the smallest element of SEQUENCE. -SEQUENCE must be a sequence of numbers or markers." - (apply #'min (seq-into sequence 'list))) +Values are compared according to the keyword argument LESSP, which +defaults to `value<' but can otherwise be any two argument function that +returns non-nil if the first argument is less than the second. The +keyword argument KEY may be a function that takes a single argument and +returns the key value used in comparison. If KEY is not specified, the +elements of SEQUENCE are compared directly." + (let* ((fresh (eval-when-compile (make-symbol "fresh"))) + (min (seq-reduce + (lambda (acc elt) + (cond + ((eq acc fresh) elt) + ((funcall lessp (funcall key acc) (funcall key elt)) acc) + (t elt))) + sequence + fresh))) + (when (eq min fresh) + (error "Cannot find minimal element of empty sequence")) + min)) ;;;###autoload -(cl-defgeneric seq-max (sequence) +(cl-defgeneric seq-max (sequence &key (key #'identity) (lessp #'value<)) "Return the largest element of SEQUENCE. -SEQUENCE must be a sequence of numbers or markers." - (apply #'max (seq-into sequence 'list))) +Values are compared according to the keyword argument LESSP, which +defaults to `value<' but can otherwise be any two argument function that +returns non-nil if the first argument is less than the second. The +keyword argument KEY may be a function that takes a single argument and +returns the key value used in comparison. If KEY is not specified, the +elements of SEQUENCE are compared directly." + (let* ((fresh (eval-when-compile (make-symbol "fresh"))) + (max (seq-reduce + (lambda (acc elt) + (cond + ((eq acc fresh) elt) + ((funcall lessp (funcall key acc) (funcall key elt)) elt) + (t elt))) + sequence + fresh))) + (when (eq max fresh) + (error "Cannot find maximal element of empty sequence")) + max)) (defun seq--count-successive (pred sequence) "Count successive elements in SEQUENCE for which PRED returns non-nil." -- 2.47.3