]> git.eshelyaron.com Git - emacs.git/commitdiff
Add new sequence function 'seq-union'
authorStefan Kangas <stefan@marxist.se>
Fri, 17 Sep 2021 08:35:13 +0000 (10:35 +0200)
committerStefan Kangas <stefan@marxist.se>
Fri, 17 Sep 2021 09:03:39 +0000 (11:03 +0200)
* 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
etc/NEWS
lisp/emacs-lisp/seq.el
lisp/emacs-lisp/shortdoc.el
test/lisp/emacs-lisp/seq-tests.el

index 20816ce8ca2d9b19e657412acfff28042182b35d..53d37199bf76dc1472c1ef2aa99b049ec93bd9be 100644 (file)
@@ -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
index eee6d2592bd3711704be5df1f40bd3e3c329d905..b1ad4dd126374ddb780c6b41fa6ea6b72244a410 100644 (file)
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3855,6 +3855,11 @@ This function is like 'require', but searches 'custom-theme-load-path'
 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
index f0dc283f57d599efe1fc593cf18171cc0ae111b9..b7dcde87f41256953330af3938cef75e3d575b0a 100644 (file)
@@ -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.
index adee6be379d38534d409bc27cf7bae13161cba34..3e0d5aef0220ef2e51e90410db82b2e7336cc2fb 100644 (file)
@@ -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
index 44e855e2cfad918174ac455c74b501ccd94d965f..bf79dd922bf133ea392186ae9b4a25538afe7cdb 100644 (file)
@@ -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]))