summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c43
-rw-r--r--lib.h3
-rw-r--r--txr.132
4 files changed, 70 insertions, 9 deletions
diff --git a/eval.c b/eval.c
index d1013871..7b8c6b35 100644
--- a/eval.c
+++ b/eval.c
@@ -6748,6 +6748,7 @@ void eval_init(void)
reg_fun(intern(lit("multi-sort"), user_package), func_n3o(multi_sort, 2));
reg_fun(intern(lit("set-diff"), user_package), func_n4o(set_diff, 2));
reg_fun(intern(lit("diff"), user_package), func_n4o(diff, 2));
+ reg_fun(intern(lit("symdiff"), user_package), func_n4o(symdiff, 2));
reg_fun(intern(lit("isec"), user_package), func_n4o(isec, 2));
reg_fun(intern(lit("uni"), user_package), func_n4o(uni, 2));
diff --git a/lib.c b/lib.c
index f5a3d920..b56a4a5b 100644
--- a/lib.c
+++ b/lib.c
@@ -9994,6 +9994,49 @@ val set_diff(val list1, val list2, val testfun, val keyfun)
return make_like(out, list_orig);
}
+val symdiff(val seq1, val seq2, val testfun, val keyfun)
+{
+ val self = lit("symdiff");
+ list_collect_decl (out, ptail);
+ seq_iter_t si1, si2;
+ val el1, el2;
+
+ testfun = default_arg(testfun, equal_f);
+ keyfun = default_arg(keyfun, identity_f);
+
+ seq_iter_init(self, &si1, seq1);
+ seq_iter_init(self, &si2, seq2);
+
+ while (seq_get(&si1, &el1))
+ ptail = list_collect(ptail, el1);
+
+ while (seq_get(&si2, &el2)) {
+ val el2_key = funcall1(keyfun, el2);
+ val *iter;
+ int found = 0;
+
+ for (iter = &out; *iter; ) {
+ val elo = us_car(*iter);
+ val elo_key = funcall1(keyfun, elo);
+ if (funcall2(testfun, elo_key, el2_key)) {
+ val del = us_cdr(*iter);
+ if (deref(ptail) == del)
+ ptail = mkcloc(*iter);
+ *iter = del;
+ found = 1;
+ break;
+ } else {
+ iter = us_cdr_p(*iter);
+ }
+ }
+
+ if (!found)
+ ptail = list_collect(ptail, el2);
+ }
+
+ return make_like(out, seq1);
+}
+
val isec(val seq1, val seq2, val testfun, val keyfun)
{
val self = lit("isec");
diff --git a/lib.h b/lib.h
index 08e7acb2..866d48b3 100644
--- a/lib.h
+++ b/lib.h
@@ -544,6 +544,8 @@ val car(val cons);
val cdr(val cons);
INLINE val us_car(val cons) { return cons->c.car; }
INLINE val us_cdr(val cons) { return cons->c.cdr; }
+INLINE val *us_car_p(val cons) { return &cons->c.car; }
+INLINE val *us_cdr_p(val cons) { return &cons->c.cdr; }
val rplaca(val cons, val new_car);
val rplacd(val cons, val new_car);
val sys_rplaca(val cons, val new_car);
@@ -1079,6 +1081,7 @@ val drop_until(val pred, val seq, val keyfun);
val in(val seq, val key, val testfun, val keyfun);
val set_diff(val list1, val list2, val testfun, val keyfun);
val diff(val seq1, val seq2, val testfun, val keyfun);
+val symdiff(val seq1, val seq2, val testfun, val keyfun);
val isec(val list1, val list2, val testfun, val keyfun);
val uni(val list1, val list2, val testfun, val keyfun);
val copy(val seq);
diff --git a/txr.1 b/txr.1
index 396019b1..1799bfba 100644
--- a/txr.1
+++ b/txr.1
@@ -28702,31 +28702,32 @@ the leftmost one is reported. See the notes under
.code pos-max
regarding duplicate maxima.
-.coNP Functions @, uni @ isec and @ diff
+.coNP Functions @, uni @, isec @ diff and @ symdiff
.synb
.mets (uni < seq1 < seq2 >> [ testfun <> [ keyfun ]])
.mets (isec < seq1 < seq2 >> [ testfun <> [ keyfun ]])
.mets (diff < seq1 < seq2 >> [ testfun <> [ keyfun ]])
+.mets (symdiff < seq1 < seq2 >> [ testfun <> [ keyfun ]])
.syne
.desc
The functions
-.codn diff ,
-.code isec
+.codn uni ,
+.codn isec ,
+.code diff
and
-.code uni
-treats the sequences
+.code symdiff
+treat the sequences
.meta seq1
and
.meta seq2
as if they were sets.
-They respectively compute the set union, set intersection
-and set difference of
+They, respectively, compute the set union, set intersection,
+set difference and symmetric difference of
.meta seq1
and
.metn seq2 ,
-returning a new sequence: the union sequence,
-intersection sequence and difference sequence.
+returning a new sequence.
The arguments
.meta seq1
@@ -28807,6 +28808,19 @@ If an element occurs at least once in
.metn seq2 ,
then it does not occur in the difference sequence.
+The symmetric difference sequence produced by
+.code symdiff
+contains all of the elements of
+.meta seq1
+which do not occur in
+.meta seq2
+and
+.IR "vice versa" :
+it also contains all of the elements of
+.meta seq2
+which do not occur in
+.metn seq1 .
+
Element equivalence is determined by a combination of
.meta testfun
and