[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
master 0cf0a2b 1/5: Add new sequence function 'seq-union'
From: |
Stefan Kangas |
Subject: |
master 0cf0a2b 1/5: Add new sequence function 'seq-union' |
Date: |
Fri, 17 Sep 2021 05:13:18 -0400 (EDT) |
branch: master
commit 0cf0a2b98671671bb7639a17639ef2552b772cbe
Author: Stefan Kangas <stefan@marxist.se>
Commit: Stefan Kangas <stefan@marxist.se>
Add new sequence function 'seq-union'
* lisp/emacs-lisp/seq.el (seq-union): New function.
* doc/lispref/sequences.texi (Sequence Functions):
* lisp/emacs-lisp/shortdoc.el (sequence): Document above new
function.
* test/lisp/emacs-lisp/seq-tests.el (test-seq-union): New test.
---
doc/lispref/sequences.texi | 16 ++++++++++++++++
etc/NEWS | 5 +++++
lisp/emacs-lisp/seq.el | 11 +++++++++++
lisp/emacs-lisp/shortdoc.el | 2 ++
test/lisp/emacs-lisp/seq-tests.el | 32 ++++++++++++++++++++++++++++++++
5 files changed, 66 insertions(+)
diff --git a/doc/lispref/sequences.texi b/doc/lispref/sequences.texi
index 20816ce..53d3719 100644
--- a/doc/lispref/sequences.texi
+++ b/doc/lispref/sequences.texi
@@ -953,6 +953,22 @@ contain less elements than @var{n}. @var{n} must be an
integer. If
@end example
@end defun
+@defun seq-union sequence1 sequence2 &optional function
+@cindex sequences, union of
+@cindex union of sequences
+ This function returns a list of the elements that appear either in
+@var{sequence1} or @var{sequence2}. If the optional argument
+@var{function} is non-@code{nil}, it is a function of two arguments to
+use to compare elements instead of the default @code{equal}.
+
+@example
+@group
+(seq-union [1 2 3] [3 5])
+@result{} (1 2 3 5)
+@end group
+@end example
+@end defun
+
@defun seq-intersection sequence1 sequence2 &optional function
@cindex sequences, intersection of
@cindex intersection of sequences
diff --git a/etc/NEWS b/etc/NEWS
index eee6d25..b1ad4dd 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3856,6 +3856,11 @@ instead of 'load-path'. It can be used by Custom themes
to load
supporting Lisp files when 'require' is unsuitable.
+++
+** New function 'seq-union'.
+This function takes two sequences and returns a list of all elements
+that appear in either of them.
+
++++
** New function 'syntax-class-to-char'.
This does almost the opposite of 'string-to-syntax' -- it returns the
syntax descriptor (a character) given a raw syntax descriptor (an
diff --git a/lisp/emacs-lisp/seq.el b/lisp/emacs-lisp/seq.el
index f0dc283..b7dcde8 100644
--- a/lisp/emacs-lisp/seq.el
+++ b/lisp/emacs-lisp/seq.el
@@ -467,6 +467,17 @@ negative integer or 0, nil is returned."
(setq sequence (seq-drop sequence n)))
(nreverse result))))
+(cl-defgeneric seq-union (sequence1 sequence2 &optional testfn)
+ "Return a list of all elements that appear in either SEQUENCE1 or SEQUENCE2.
+Equality is defined by TESTFN if non-nil or by `equal' if nil."
+ (let ((accum (lambda (acc elt)
+ (if (seq-contains-p acc elt testfn)
+ acc
+ (cons elt acc)))))
+ (seq-reverse
+ (seq-reduce accum sequence2
+ (seq-reduce accum sequence1 '())))))
+
;;;###autoload
(cl-defgeneric seq-intersection (sequence1 sequence2 &optional testfn)
"Return a list of the elements that appear in both SEQUENCE1 and SEQUENCE2.
diff --git a/lisp/emacs-lisp/shortdoc.el b/lisp/emacs-lisp/shortdoc.el
index adee6be..3e0d5ae 100644
--- a/lisp/emacs-lisp/shortdoc.el
+++ b/lisp/emacs-lisp/shortdoc.el
@@ -809,6 +809,8 @@ There can be any number of :example/:result elements."
:eval (seq-remove #'numberp '(1 2 c d 5)))
(seq-group-by
:eval (seq-group-by #'cl-plusp '(-1 2 3 -4 -5 6)))
+ (seq-union
+ :eval (seq-union '(1 2 3) '(3 5)))
(seq-difference
:eval (seq-difference '(1 2 3) '(2 3 4)))
(seq-intersection
diff --git a/test/lisp/emacs-lisp/seq-tests.el
b/test/lisp/emacs-lisp/seq-tests.el
index 44e855e..bf79dd9 100644
--- a/test/lisp/emacs-lisp/seq-tests.el
+++ b/test/lisp/emacs-lisp/seq-tests.el
@@ -336,6 +336,38 @@ Evaluate BODY for each created sequence.
(should (same-contents-p list vector))
(should (vectorp vector))))
+(ert-deftest test-seq-union ()
+ (let ((v1 '(1 2 3))
+ (v2 '(3 5)))
+ (should (same-contents-p (seq-union v1 v2)
+ '(1 2 3 5))))
+
+ (let ((v1 '(1 2 3 4 5 6))
+ (v2 '(4 5 6 7 8 9)))
+ (should (same-contents-p (seq-union v1 v2)
+ '(1 2 3 4 5 6 7 8 9))))
+
+ (let ((v1 '(1 2 3 4 5 6))
+ (v2 '(4 5 6 7 8 9)))
+ (should (same-contents-p (seq-union v1 v2)
+ '(1 2 3 4 5 6 7 8 9))))
+
+ (let ((v1 [1 2 3 4 5])
+ (v2 [4 5 6 "a"]))
+ (should (same-contents-p (seq-union v1 v2)
+ '(1 2 3 4 5 6 "a"))))
+
+ (let ((v1 '("a" "b" "c"))
+ (v2 '("f" "c" "e" "a")))
+ (should (same-contents-p (seq-union v1 v2)
+ '("a" "b" "c" "f" "e"))))
+
+ (let ((v1 '("a"))
+ (v2 '("a"))
+ (testfn #'eq))
+ (should (same-contents-p (seq-union v1 v2 testfn)
+ '("a" "a")))))
+
(ert-deftest test-seq-intersection ()
(let ((v1 [2 3 4 5])
(v2 [1 3 5 6 7]))