summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Cassou <damien@cassou.me>2016-10-21 07:53:08 +0200
committerNicolas Petton <nicolas@petton.fr>2016-10-25 12:32:57 +0200
commitbd22beb6e4054c659e8c31931c421f60e9719c65 (patch)
treec9afbd41266dc8c13a9807bf825d68cdbc148687
parent26ccd19269c040ad5960a7567aa5fc88f142c709 (diff)
downloademacs-bd22beb6e4054c659e8c31931c421f60e9719c65.tar.gz
Add seq-random-elt to seq.el
* lisp/emacs-lisp/seq.el (seq-random-elt): Add function to return a random element from it's sequence parameter. * test/lisp/emacs-lisp/seq-tests.el (test-seq-random-elt-take-all test-seq-random-elt-return-nil): Test the new function * doc/lispref/sequences.texi: Document the new function
-rw-r--r--doc/lispref/sequences.texi20
-rw-r--r--lisp/emacs-lisp/seq.el9
-rw-r--r--test/lisp/emacs-lisp/seq-tests.el17
3 files changed, 45 insertions, 1 deletions
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index 08e5e3ae35c..b6874bf72e4 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -1037,6 +1037,26 @@ followed by a variable name to be bound to the rest of
@end example
@end defmac
+@defun seq-random-elt sequence
+ This function returns an element of @var{sequence} taken at random. If @var{sequence} is nil, the function returns nil.
+
+@example
+@group
+(seq-random-elt [1 2 3 4])
+@result{} 3
+(seq-random-elt [1 2 3 4])
+@result{} 2
+(seq-random-elt [1 2 3 4])
+@result{} 4
+(seq-random-elt [1 2 3 4])
+@result{} 2
+(seq-random-elt [1 2 3 4])
+@result{} 1
+@end group
+@end example
+
+ If @var{sequence} is empty, the function signals an error.
+@end defun
@node Arrays
@section Arrays
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index 85702f4a64d..5c89d2b3007 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -4,7 +4,7 @@
;; Author: Nicolas Petton <nicolas@petton.fr>
;; Keywords: sequences
-;; Version: 2.18
+;; Version: 2.19
;; Package: seq
;; Maintainer: emacs-devel@gnu.org
@@ -476,6 +476,13 @@ SEQUENCE must be a sequence of numbers or markers."
"Return element of SEQUENCE at the index N.
If no element is found, return nil."
(ignore-errors (seq-elt sequence n)))
+
+(cl-defgeneric seq-random-elt (sequence)
+ "Return a random element from SEQUENCE.
+Return nil if SEQUENCE is nil."
+ (if (seq-empty-p sequence)
+ (error "Sequence cannot be empty")
+ (seq-elt sequence (random (seq-length sequence)))))
;;; Optimized implementations for lists
diff --git a/test/lisp/emacs-lisp/seq-tests.el b/test/lisp/emacs-lisp/seq-tests.el
index c2065c6718f..6d17b7c7c97 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -28,6 +28,7 @@
(require 'ert)
(require 'seq)
+(require 'map)
(defmacro with-test-sequences (spec &rest body)
"Successively bind VAR to a list, vector, and string built from SEQ.
@@ -371,5 +372,21 @@ Evaluate BODY for each created sequence.
(should (equal (seq-sort-by #'seq-length #'> seq)
["xxx" "xx" "x"]))))
+(ert-deftest test-seq-random-elt-take-all ()
+ (let ((seq '(a b c d e))
+ (count '()))
+ (should (= 0 (map-length count)))
+ (dotimes (_ 1000)
+ (let ((random-elt (seq-random-elt seq)))
+ (map-put count
+ random-elt
+ (map-elt count random-elt 0))))
+ (should (= 5 (map-length count)))))
+
+(ert-deftest test-seq-random-elt-signal-on-empty ()
+ (should-error (seq-random-elt nil))
+ (should-error (seq-random-elt []))
+ (should-error (seq-random-elt "")))
+
(provide 'seq-tests)
;;; seq-tests.el ends here