]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new function `seq-positions'
authorDamien Cassou <damien@cassou.me>
Sun, 4 Sep 2022 11:21:59 +0000 (13:21 +0200)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 4 Sep 2022 11:21:59 +0000 (13:21 +0200)
* 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).

doc/lispref/sequences.texi
etc/NEWS
lisp/emacs-lisp/seq.el
lisp/emacs-lisp/shortdoc.el
test/lisp/emacs-lisp/seq-tests.el

index 2ee19efb1a99e5fe454af481f2d89054550a448d..214b1e76e157e0798d8e69c832b7ceea4d0c6362 100644 (file)
@@ -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
index ee450317a0c8536eca9cd1cf4615a5794251f4b7..6c0cf19fe6b177f0dd715f3fc106a49b33f1ccfe 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2742,6 +2742,11 @@ compiler now emits a warning about this deprecated usage.
 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
index 64197b55e5f977b21f139f610b2ff6c537e37aaf..31dcfa98b4040be9d0b0e6048ccc9fb8319328da 100644 (file)
@@ -459,6 +459,23 @@ Equality is defined by the function TESTFN, which defaults to `equal'."
         (setq index (1+ index)))
       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.
index 6a366ec0fc09f72876b28df2d152796fc67e09ed..2472479bad682a277ced8e62c2262d00963075fe 100644 (file)
@@ -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
index 6249e486173c7341c0be6351eb77029026cc92fb..d95b35c45eb97975207046e1dd7e26e6138a4e2b 100644 (file)
@@ -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)