>From e3c696f73b37da24eb3883d365a72f014a3e52ee Mon Sep 17 00:00:00 2001 From: Damien Cassou Date: Fri, 2 Sep 2022 14:54:36 +0200 Subject: [PATCH] Add new function `seq-positions' * doc/lispref/sequences.texi (Sequence Functions): Document it. * lisp/emacs-lisp/seq.el (seq-positions): New function. * lisp/emacs-lisp/shortdoc.el (sequence): Mention it. * test/lisp/emacs-lisp/seq-tests.el (test-seq-positions): Test it. --- doc/lispref/sequences.texi | 17 +++++++++++++++++ etc/NEWS | 5 +++++ lisp/emacs-lisp/seq.el | 13 +++++++++++++ lisp/emacs-lisp/shortdoc.el | 3 +++ test/lisp/emacs-lisp/seq-tests.el | 5 +++++ 5 files changed, 43 insertions(+) diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1f6f80521c..6b198ba731 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -880,6 +880,23 @@ Sequence Functions @end example @end defun +@defun seq-positions sequence elt &optional testfn + This function returns a list of the (zero-based) indices of the +elements in @var{sequence} that are equal to @var{elt}. If the +optional argument @var{testfn} is non-@code{nil}, it is a function of +two arguments to use instead of the default @code{equal}. + +@example +@group +(seq-positions '(a b c a d) 'a) +@result{} (0 3) +@end group +@group +(seq-positions '(a b c a d) 'z) +@result{} nil +@end group +@end example +@end defun @defun seq-uniq sequence &optional function This function returns a list of the elements of @var{sequence} with diff --git a/etc/NEWS b/etc/NEWS index 1512d45fdc..a8fc8dcc34 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -2710,6 +2710,11 @@ The default timeout value can be defined by the new variable ** New function 'seq-split'. This returns a list of sub-sequences of the specified sequence. ++++ +** New function 'seq-positions'. +This returns a list of the (zero-based) indices of a given element in +the specified sequence. + +++ ** 'plist-get', 'plist-put' and 'plist-member' are no longer limited to 'eq'. These function now take an optional comparison predicate argument. diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index b6f0f66e5b..7e8576fffb 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el @@ -445,6 +445,19 @@ seq-position (setq index (1+ index))) nil))) +;;;###autoload +(cl-defgeneric seq-positions (sequence elt &optional testfn) + "Return a list of the (zero-based) indices of ELT in SEQ. +Equality is defined by the function TESTFN, which defaults to +`equal'." + (let ((result '())) + (seq-do-indexed + (lambda (e index) + (when (funcall (or testfn #'equal) e elt) + (push index result))) + sequence) + (nreverse result))) + ;;;###autoload (cl-defgeneric seq-uniq (sequence &optional testfn) "Return a list of the elements of SEQUENCE with duplicates removed. diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el index 990dabe351..80b9c0a69e 100644 --- a/lisp/emacs-lisp/shortdoc.el +++ b/lisp/emacs-lisp/shortdoc.el @@ -846,6 +846,9 @@ sequence :eval (seq-find #'numberp '(a b 3 4 f 6))) (seq-position :eval (seq-position '(a b c) 'c)) + (seq-positions + :eval (seq-positions '(a b c a d) 'a) + :eval (seq-positions '(a b c a d) 'z)) (seq-length :eval (seq-length "abcde")) (seq-max diff --git a/test/lisp/emacs-lisp/seq-tests.el b/test/lisp/emacs-lisp/seq-tests.el index 1a27467d29..7f06a7e618 100644 --- a/test/lisp/emacs-lisp/seq-tests.el +++ b/test/lisp/emacs-lisp/seq-tests.el @@ -482,6 +482,11 @@ test-seq-position (should (= (seq-position seq 'a #'eq) 0)) (should (null (seq-position seq (make-symbol "a") #'eq))))) +(ert-deftest test-seq-positions () + (with-test-sequences (seq '(1 2 3 1 4)) + (should (equal '(0 3) (seq-positions seq 1))) + (should (seq-empty-p (seq-positions seq 9))))) + (ert-deftest test-seq-sort-by () (let ((seq ["x" "xx" "xxx"])) (should (equal (seq-sort-by #'seq-length #'> seq) -- 2.36.2