diff options
| author | Nicolas Petton | 2015-04-15 00:33:27 +0200 |
|---|---|---|
| committer | Nicolas Petton | 2015-04-15 01:55:03 +0200 |
| commit | 17d667b3876920652152baa4eab24134940a0f30 (patch) | |
| tree | e7c8dcebf8bfc976e7212c84dc54b53ae3ced477 | |
| parent | 4191e54fc63be623b3a25081ab9fe03d28615fea (diff) | |
| download | emacs-17d667b3876920652152baa4eab24134940a0f30.tar.gz emacs-17d667b3876920652152baa4eab24134940a0f30.zip | |
Add seq-intersection and seq-difference to the seq library
* lisp/emacs-lisp/seq.el (seq-intersection, seq-difference): New
functions.
* test/automated/seq-tests.el: Add tests for seq-intersection and
seq-difference.
* doc/lispref/sequences.texi: Add documentation for seq-intersection
and seq-difference.
| -rw-r--r-- | doc/lispref/sequences.texi | 30 | ||||
| -rw-r--r-- | lisp/emacs-lisp/seq.el | 29 | ||||
| -rw-r--r-- | test/automated/seq-tests.el | 26 |
3 files changed, 83 insertions, 2 deletions
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi index 1af353590cf..334b3478cb6 100644 --- a/doc/lispref/sequences.texi +++ b/doc/lispref/sequences.texi | |||
| @@ -723,6 +723,35 @@ contain less elements than @var{n}. @var{n} must be an integer. If | |||
| 723 | @end example | 723 | @end example |
| 724 | @end defun | 724 | @end defun |
| 725 | 725 | ||
| 726 | @defun seq-intersection sequence1 sequence2 &optional function | ||
| 727 | This function returns a list of the elements that appear both in | ||
| 728 | @var{sequence1} and @var{sequence2}. If the optional argument | ||
| 729 | @var{function} is non-@code{nil}, it is a function of two arguments to | ||
| 730 | use to compare elements instead of the default @code{equal}. | ||
| 731 | |||
| 732 | @example | ||
| 733 | @group | ||
| 734 | (seq-intersection [2 3 4 5] [1 3 5 6 7]) | ||
| 735 | @result {} (3 5) | ||
| 736 | @end group | ||
| 737 | @end example | ||
| 738 | @end defun | ||
| 739 | |||
| 740 | |||
| 741 | @defun seq-difference sequence1 sequence2 &optional function | ||
| 742 | This function returns a list of the elements that appear in | ||
| 743 | @var{sequence1} but not in @var{sequence2}. If the optional argument | ||
| 744 | @var{function} is non-@code{nil}, it is a function of two arguments to | ||
| 745 | use to compare elements instead of the default @code{equal}. | ||
| 746 | |||
| 747 | @example | ||
| 748 | @group | ||
| 749 | (seq-difference '(2 3 4 5) [1 3 5 6 7]) | ||
| 750 | @result {} (2 4) | ||
| 751 | @end group | ||
| 752 | @end example | ||
| 753 | @end defun | ||
| 754 | |||
| 726 | @defun seq-group-by function sequence | 755 | @defun seq-group-by function sequence |
| 727 | This function separates the elements of @var{sequence} into an alist | 756 | This function separates the elements of @var{sequence} into an alist |
| 728 | whose keys are the result of applying @var{function} to each element | 757 | whose keys are the result of applying @var{function} to each element |
| @@ -761,7 +790,6 @@ of type @var{type}. @var{type} can be one of the following symbols: | |||
| 761 | @end example | 790 | @end example |
| 762 | @end defun | 791 | @end defun |
| 763 | 792 | ||
| 764 | |||
| 765 | @defmac seq-doseq (var sequence [result]) body@dots{} | 793 | @defmac seq-doseq (var sequence [result]) body@dots{} |
| 766 | @cindex sequence iteration | 794 | @cindex sequence iteration |
| 767 | This macro is like @code{dolist}, except that @var{sequence} can be a list, | 795 | This macro is like @code{dolist}, except that @var{sequence} can be a list, |
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el index c5f5906e7e5..6f7f3c46e2a 100644 --- a/lisp/emacs-lisp/seq.el +++ b/lisp/emacs-lisp/seq.el | |||
| @@ -4,7 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | ;; Author: Nicolas Petton <nicolas@petton.fr> | 5 | ;; Author: Nicolas Petton <nicolas@petton.fr> |
| 6 | ;; Keywords: sequences | 6 | ;; Keywords: sequences |
| 7 | ;; Version: 1.3 | 7 | ;; Version: 1.4 |
| 8 | ;; Package: seq | 8 | ;; Package: seq |
| 9 | 9 | ||
| 10 | ;; Maintainer: emacs-devel@gnu.org | 10 | ;; Maintainer: emacs-devel@gnu.org |
| @@ -240,6 +240,26 @@ negative integer or 0, nil is returned." | |||
| 240 | (setq seq (seq-drop seq n))) | 240 | (setq seq (seq-drop seq n))) |
| 241 | (nreverse result)))) | 241 | (nreverse result)))) |
| 242 | 242 | ||
| 243 | (defun seq-intersection (seq1 seq2 &optional testfn) | ||
| 244 | "Return a list of the elements that appear in both SEQ1 and SEQ2. | ||
| 245 | Equality is defined by TESTFN if non-nil or by `equal' if nil." | ||
| 246 | (seq-reduce (lambda (acc elt) | ||
| 247 | (if (seq-contains-p seq2 elt testfn) | ||
| 248 | (cons elt acc) | ||
| 249 | acc)) | ||
| 250 | (seq-reverse seq1) | ||
| 251 | '())) | ||
| 252 | |||
| 253 | (defun seq-difference (seq1 seq2 &optional testfn) | ||
| 254 | "Return a list of th elements that appear in SEQ1 but not in SEQ2. | ||
| 255 | Equality is defined by TESTFN if non-nil or by `equal' if nil." | ||
| 256 | (seq-reduce (lambda (acc elt) | ||
| 257 | (if (not (seq-contains-p seq2 elt testfn)) | ||
| 258 | (cons elt acc) | ||
| 259 | acc)) | ||
| 260 | (seq-reverse seq1) | ||
| 261 | '())) | ||
| 262 | |||
| 243 | (defun seq-group-by (function seq) | 263 | (defun seq-group-by (function seq) |
| 244 | "Apply FUNCTION to each element of SEQ. | 264 | "Apply FUNCTION to each element of SEQ. |
| 245 | Separate the elements of SEQ into an alist using the results as | 265 | Separate the elements of SEQ into an alist using the results as |
| @@ -318,6 +338,11 @@ This is an optimization for lists in `seq-take-while'." | |||
| 318 | (setq n (+ 1 n))) | 338 | (setq n (+ 1 n))) |
| 319 | n)) | 339 | n)) |
| 320 | 340 | ||
| 341 | (defun seq--activate-font-lock-keywords () | ||
| 342 | "Activate font-lock keywords for some symbols defined in seq." | ||
| 343 | (font-lock-add-keywords 'emacs-lisp-mode | ||
| 344 | '("\\<seq-doseq\\>"))) | ||
| 345 | |||
| 321 | (defalias 'seq-copy #'copy-sequence) | 346 | (defalias 'seq-copy #'copy-sequence) |
| 322 | (defalias 'seq-elt #'elt) | 347 | (defalias 'seq-elt #'elt) |
| 323 | (defalias 'seq-length #'length) | 348 | (defalias 'seq-length #'length) |
| @@ -325,5 +350,7 @@ This is an optimization for lists in `seq-take-while'." | |||
| 325 | (defalias 'seq-each #'seq-do) | 350 | (defalias 'seq-each #'seq-do) |
| 326 | (defalias 'seq-map #'mapcar) | 351 | (defalias 'seq-map #'mapcar) |
| 327 | 352 | ||
| 353 | (add-to-list 'emacs-lisp-mode-hook #'seq--activate-font-lock-keywords) | ||
| 354 | |||
| 328 | (provide 'seq) | 355 | (provide 'seq) |
| 329 | ;;; seq.el ends here | 356 | ;;; seq.el ends here |
diff --git a/test/automated/seq-tests.el b/test/automated/seq-tests.el index d3536b6f9a6..7f6e06cc4b6 100644 --- a/test/automated/seq-tests.el +++ b/test/automated/seq-tests.el | |||
| @@ -250,5 +250,31 @@ Evaluate BODY for each created sequence. | |||
| 250 | (should (same-contents-p list vector)) | 250 | (should (same-contents-p list vector)) |
| 251 | (should (vectorp vector)))) | 251 | (should (vectorp vector)))) |
| 252 | 252 | ||
| 253 | (ert-deftest test-seq-intersection () | ||
| 254 | (let ((v1 [2 3 4 5]) | ||
| 255 | (v2 [1 3 5 6 7])) | ||
| 256 | (should (same-contents-p (seq-intersection v1 v2) | ||
| 257 | '(3 5)))) | ||
| 258 | (let ((l1 '(2 3 4 5)) | ||
| 259 | (l2 '(1 3 5 6 7))) | ||
| 260 | (should (same-contents-p (seq-intersection l1 l2) | ||
| 261 | '(3 5)))) | ||
| 262 | (let ((v1 [2 4 6]) | ||
| 263 | (v2 [1 3 5])) | ||
| 264 | (should (seq-empty-p (seq-intersection v1 v2))))) | ||
| 265 | |||
| 266 | (ert-deftest test-seq-difference () | ||
| 267 | (let ((v1 [2 3 4 5]) | ||
| 268 | (v2 [1 3 5 6 7])) | ||
| 269 | (should (same-contents-p (seq-difference v1 v2) | ||
| 270 | '(2 4)))) | ||
| 271 | (let ((l1 '(2 3 4 5)) | ||
| 272 | (l2 '(1 3 5 6 7))) | ||
| 273 | (should (same-contents-p (seq-difference l1 l2) | ||
| 274 | '(2 4)))) | ||
| 275 | (let ((v1 [2 4 6]) | ||
| 276 | (v2 [2 4 6])) | ||
| 277 | (should (seq-empty-p (seq-difference v1 v2))))) | ||
| 278 | |||
| 253 | (provide 'seq-tests) | 279 | (provide 'seq-tests) |
| 254 | ;;; seq-tests.el ends here | 280 | ;;; seq-tests.el ends here |