[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master b31680ef04 1/2: Add new function `seq-split'
From: |
Lars Ingebrigtsen |
Subject: |
master b31680ef04 1/2: Add new function `seq-split' |
Date: |
Sun, 3 Jul 2022 07:00:01 -0400 (EDT) |
branch: master
commit b31680ef040d4a232619e8d070794a43d2cdca2c
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>
Add new function `seq-split'
* doc/lispref/sequences.texi (Sequence Functions): Document it.
* lisp/emacs-lisp/seq.el (seq-split): New function.
* lisp/emacs-lisp/shortdoc.el (sequence): Mention it.
---
doc/lispref/sequences.texi | 14 ++++++++++++++
etc/NEWS | 4 ++++
lisp/emacs-lisp/seq.el | 15 +++++++++++++++
lisp/emacs-lisp/shortdoc.el | 2 ++
test/lisp/emacs-lisp/seq-tests.el | 21 +++++++++++++++++++++
5 files changed, 56 insertions(+)
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index c3f4cff301..39230d0adc 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -577,6 +577,20 @@ starting from the first one for which @var{predicate}
returns @code{nil}.
@end example
@end defun
+@defun seq-split sequence length
+ This function returns a list consisting of sub-sequences of
+@var{sequence} of (at most) length @var{length}. (The final element
+may be shorter than @var{length} if the length of @var{sequence} isn't
+a multiple of @var{length}.
+
+@example
+@group
+(seq-split [0 1 2 3 4] 2)
+@result{} ([0 1] [2 3] [4])
+@end group
+@end example
+@end defun
+
@defun seq-do function sequence
This function applies @var{function} to each element of
@var{sequence} in turn (presumably for side effects), and returns
diff --git a/etc/NEWS b/etc/NEWS
index af3240e504..e1cdbd5077 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -2250,6 +2250,10 @@ patcomp.el, pc-mode.el, pc-select.el, s-region.el, and
sregex.el.
* Lisp Changes in Emacs 29.1
++++
+** New function 'seq-split'.
+This returns a list of sub-sequences of 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 947b64e868..36c17f4cd5 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -632,5 +632,20 @@ Signal an error if SEQUENCE is empty."
;; we automatically highlight macros.
(add-hook 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords))
+(defun seq-split (sequence length)
+ "Split SEQUENCE into a list of sub-sequences of at most LENGTH.
+All the sub-sequences will be of LENGTH, except the last one,
+which may be shorter."
+ (when (< length 1)
+ (error "Sub-sequence length must be larger than zero"))
+ (let ((result nil)
+ (seq-length (length sequence))
+ (start 0))
+ (while (< start seq-length)
+ (push (seq-subseq sequence start
+ (setq start (min seq-length (+ start length))))
+ result))
+ (nreverse result)))
+
(provide 'seq)
;;; seq.el ends here
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index c82aa3365c..f53e783111 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -889,6 +889,8 @@ A FUNC form can have any number of `:no-eval' (or
`:no-value'),
:eval (seq-subseq '(a b c d e) 2 4))
(seq-take
:eval (seq-take '(a b c d e) 3))
+ (seq-split
+ :eval (seq-split [0 1 2 3 5] 2))
(seq-take-while
:eval (seq-take-while #'cl-evenp [2 4 9 6 5]))
(seq-uniq
diff --git a/test/lisp/emacs-lisp/seq-tests.el
b/test/lisp/emacs-lisp/seq-tests.el
index 9e5d59163f..d979604910 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -511,5 +511,26 @@ Evaluate BODY for each created sequence.
(should (equal (seq-difference '(1 nil) '(2 nil))
'(1)))))
+(ert-deftest test-seq-split ()
+ (let ((seq [0 1 2 3 4 5 6 7 8 9 10]))
+ (should (equal seq (car (seq-split seq 20))))
+ (should (equal seq (car (seq-split seq 11))))
+ (should (equal (seq-split seq 10)
+ '([0 1 2 3 4 5 6 7 8 9] [10])))
+ (should (equal (seq-split seq 5)
+ '([0 1 2 3 4] [5 6 7 8 9] [10])))
+ (should (equal (seq-split seq 1)
+ '([0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10])))
+ (should-error (seq-split seq 0))
+ (should-error (seq-split seq -10)))
+ (let ((seq '(0 1 2 3 4 5 6 7 8 9)))
+ (should (equal (seq-split seq 5)
+ '((0 1 2 3 4) (5 6 7 8 9)))))
+ (let ((seq "0123456789"))
+ (should (equal (seq-split seq 2)
+ '("01" "23" "45" "67" "89")))
+ (should (equal (seq-split seq 3)
+ '("012" "345" "678" "9")))))
+
(provide 'seq-tests)
;;; seq-tests.el ends here