summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Cassou <damien@cassou.me>2022-09-04 13:21:59 +0200
committerLars Ingebrigtsen <larsi@gnus.org>2022-09-04 13:21:59 +0200
commit4751b51d5e1182975aa002af08a625e4859ec276 (patch)
tree1dcabd8ede4a44d931d998dca9ddba21d2faa324
parent4d50d413e67dd8ae183af8b68f315a667ebf2add (diff)
downloademacs-4751b51d5e1182975aa002af08a625e4859ec276.tar.gz
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 (bug#57548).
-rw-r--r--doc/lispref/sequences.texi21
-rw-r--r--etc/NEWS5
-rw-r--r--lisp/emacs-lisp/seq.el17
-rw-r--r--lisp/emacs-lisp/shortdoc.el4
-rw-r--r--test/lisp/emacs-lisp/seq-tests.el7
5 files changed, 54 insertions, 0 deletions
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index 2ee19efb1a9..214b1e76e15 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -898,6 +898,27 @@ use instead of the default @code{equal}.
@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} for which @var{testfn} returns
+non-@code{nil} when passed the element and @var{elt} as
+arguments. @var{testfn} defaults to @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
+@group
+(seq-positions '(11 5 7 12 9 15) 10 #'>=)
+@result{} (0 3 5)
+@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 ee450317a0c..6c0cf19fe6b 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2743,6 +2743,11 @@ These can be used for buttons in buffers and the like. See the
"(elisp) Icons" and "(emacs) Icons" nodes in the manuals for details.
+++
+** New function 'seq-positions'.
+This returns a list of the (zero-based) indices of elements matching a
+given predicate in the specified sequence.
+
++++
** New arguments MESSAGE and TIMEOUT of 'set-transient-map'.
MESSAGE specifies a message to display after activating the transient
map, including a special formatting spec to list available keys.
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index 64197b55e5f..31dcfa98b40 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -460,6 +460,23 @@ Equality is defined by the function TESTFN, which defaults to `equal'."
nil)))
;;;###autoload
+(cl-defgeneric seq-positions (sequence elt &optional testfn)
+ "Return indices for which (TESTFN (seq-elt SEQUENCE index) ELT) is non-nil.
+
+TESTFN is a two-argument function which is passed each element of
+SEQUENCE as first argument and ELT as second. TESTFN defaults to
+`equal'.
+
+The result is a list of (zero-based) indices."
+ (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.
TESTFN is used to compare elements, or `equal' if TESTFN is nil."
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index 6a366ec0fc0..2472479bad6 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -846,6 +846,10 @@ A FUNC form can have any number of `:no-eval' (or `:no-value'),
: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)
+ :eval (seq-positions '(11 5 7 12 9 15) 10 #'>=))
(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 6249e486173..d95b35c45eb 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -490,6 +490,13 @@ Evaluate BODY for each created sequence.
(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))))
+ (with-test-sequences (seq '(11 5 7 12 9 15))
+ (should (equal '(0 3 5) (seq-positions seq 10 #'>=)))))
+
(ert-deftest test-seq-sort-by ()
(let ((seq ["x" "xx" "xxx"]))
(should (equal (seq-sort-by #'seq-length #'> seq)