From 8aa0386420f9d982b99568f27a5953dfc737640e Mon Sep 17 00:00:00 2001 From: Nicolas Petton Date: Thu, 10 Sep 2015 23:49:56 +0200 Subject: [PATCH] Add seq-find This function is similar to `seq-some' but returns the found element. In the cases where nil can be the found element, a sentinel optional argument can be provided to avoid ambiguities. * lisp/emacs-lisp/seq.el (seq-find): New function. * test/automated/seq-tests.el (test-seq-find): Add tests for `seq-find'. * doc/lispref/sequences.texi (Sequence Functions): Add documentation for seq-find. --- doc/lispref/sequences.texi | 22 ++++++++++++++++++++++ lisp/emacs-lisp/seq.el | 13 +++++++++++++ test/automated/seq-tests.el | 10 ++++++++++ 3 files changed, 45 insertions(+) diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index f73779bd9ce..d0190457179 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi @@ -578,6 +578,28 @@ value is the value returned by @var{predicate}. @end example @end defun +@defun seq-find predicate sequence &optional sentinel + This function returns the first element for which @var{predicate} +returns non-@code{nil} in @var{sequence}. If no element matches +@var{predicate}, @var{sentinel} is returned if non-@code{nil}, +@code{nil} otherwise. + +Note that this function has an ambiguity if the found element is +@code{nil}, and if no @var{sentinel} is specified, as it cannot be +known if an element was found or not. + +@example +@group +(seq-find #'numberp ["abc" 1 nil]) +@result{} 1 +@end group +@group +(seq-find #'numberp ["abc" "def"]) +@result{} nil +@end group +@end example +@end defun + @defun seq-every-p predicate sequence This function returns non-@code{nil} if applying @var{predicate} to every element of @var{sequence} returns non-@code{nil}. diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index 751c18f4aae..4b50a0a9b7b 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el @@ -270,6 +270,19 @@ If so, return the non-nil value returned by PRED." (throw 'seq--break result)))) nil)) +(cl-defgeneric seq-find (pred seq &optional sentinel) + "Return the first element for which (PRED element) is non-nil in SEQ. +If no element is found, return SENTINEL or nil. + +Note that `seq-find' has an ambiguity if the found element is nil +and if no SENTINEL is specified, as it cannot be known if an +element was found or not." + (catch 'seq--break + (seq-doseq (elt seq) + (when (funcall pred elt) + (throw 'seq--break elt))) + sentinel)) + (cl-defgeneric seq-count (pred seq) "Return the number of elements for which (PRED element) is non-nil in SEQ." (let ((count 0)) diff --git a/test/automated/seq-tests.el b/test/automated/seq-tests.el index 07a183d024e..7023c94c0c7 100644 --- a/test/automated/seq-tests.el +++ b/test/automated/seq-tests.el @@ -138,6 +138,16 @@ Evaluate BODY for each created sequence. (should-not (seq-some #'test-sequences-oddp seq))) (should (seq-some #'null '(1 nil 2)))) +(ert-deftest test-seq-find () + (with-test-sequences (seq '(4 3 2 1)) + (should (= 4 (seq-find #'test-sequences-evenp seq))) + (should (= 3 (seq-find #'test-sequences-oddp seq))) + (should-not (seq-find (lambda (elt) (> elt 10)) seq))) + (should-not (seq-find #'null '(1 nil 2))) + (should-not (seq-find #'null '(1 nil 2) t)) + (should-not (seq-find #'null '(1 2 3))) + (should (seq-find #'null '(1 2 3) 'sentinel))) + (ert-deftest test-seq-contains () (with-test-sequences (seq '(3 4 5 6)) (should (seq-contains seq 3)) -- 2.39.2