summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c5
-rw-r--r--lib.c105
-rw-r--r--lib.h1
-rw-r--r--txr.139
4 files changed, 109 insertions, 41 deletions
diff --git a/eval.c b/eval.c
index f9150b8c..d1013871 100644
--- a/eval.c
+++ b/eval.c
@@ -6014,7 +6014,6 @@ void eval_init(void)
val not_null_f = func_n1(not_null);
val me_each_f = func_n2(me_each);
val me_for_f = func_n2(me_for);
- val diff_f = func_n4o(set_diff, 2);
val length_f = func_n1(length);
protect(&top_vb, &top_fb, &top_mb, &top_smb, &special, &builtin, &dyn_env,
@@ -6747,8 +6746,8 @@ void eval_init(void)
reg_fun(intern(lit("find-max"), user_package), func_n3o(find_max, 1));
reg_fun(intern(lit("find-min"), user_package), func_n3o(find_min, 1));
reg_fun(intern(lit("multi-sort"), user_package), func_n3o(multi_sort, 2));
- reg_fun(intern(lit("set-diff"), user_package), diff_f);
- reg_fun(intern(lit("diff"), user_package), diff_f);
+ 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("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 8697fdc0..f5a3d920 100644
--- a/lib.c
+++ b/lib.c
@@ -9930,6 +9930,42 @@ val in(val seq, val item, val testfun, val keyfun)
}
}
+val diff(val seq1, val seq2, val testfun, val keyfun)
+{
+ val self = lit("diff");
+ list_collect_decl (out, ptail);
+ seq_iter_t si1, si2;
+ val el1;
+
+ 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)) {
+ val el1_key = funcall1(keyfun, el1);
+ val el2;
+ int found = 0;
+
+ seq_iter_rewind(self, &si2);
+
+ while (seq_get(&si2, &el2)) {
+ val el2_key = funcall1(keyfun, el2);
+
+ if (funcall2(testfun, el1_key, el2_key)) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ ptail = list_collect(ptail, el1);
+ }
+
+ return make_like(out, seq1);
+}
+
val set_diff(val list1, val list2, val testfun, val keyfun)
{
list_collect_decl (out, ptail);
@@ -9958,63 +9994,62 @@ val set_diff(val list1, val list2, val testfun, val keyfun)
return make_like(out, list_orig);
}
-val isec(val list1, val list2, val testfun, val keyfun)
+val isec(val seq1, val seq2, val testfun, val keyfun)
{
+ val self = lit("isec");
list_collect_decl (out, ptail);
- val list_orig = list1;
-
- list1 = nullify(list1);
- list2 = nullify(list2);
+ seq_iter_t si1, si2;
+ val el1;
testfun = default_arg(testfun, equal_f);
keyfun = default_arg(keyfun, identity_f);
- for (; list1; list1 = cdr(list1)) {
- /* optimization: list2 is a tail of list1, and so we
- are done, unless the application has a weird test function. */
- if (list1 == list2) {
- ptail = list_collect_append(ptail, list1);
- break;
- } else {
- val item = car(list1);
- val list1_key = funcall1(keyfun, item);
+ seq_iter_init(self, &si1, seq1);
+ seq_iter_init(self, &si2, seq2);
- if (member(list1_key, list2, testfun, keyfun))
- ptail = list_collect(ptail, item);
+ while (seq_get(&si1, &el1)) {
+ val el1_key = funcall1(keyfun, el1);
+ val el2;
+
+ seq_iter_rewind(self, &si2);
+
+ while (seq_get(&si2, &el2)) {
+ val el2_key = funcall1(keyfun, el2);
+
+ if (funcall2(testfun, el1_key, el2_key)) {
+ ptail = list_collect(ptail, el1);
+ break;
+ }
}
}
- return make_like(out, list_orig);
+ return make_like(out, seq1);
}
-val uni(val list1, val list2, val testfun, val keyfun)
+val uni(val seq1, val seq2, val testfun, val keyfun)
{
+ val self = lit("uni");
list_collect_decl (out, ptail);
- val list_orig = list1;
-
- list1 = nullify(list1);
- list2 = nullify(list2);
+ seq_iter_t si1, si2;
+ val el1, el2;
testfun = default_arg(testfun, equal_f);
keyfun = default_arg(keyfun, identity_f);
- ptail = list_collect_append(ptail, list1);
+ seq_iter_init(self, &si1, seq1);
+ seq_iter_init(self, &si2, seq2);
- for (; list2; list2 = cdr(list2)) {
- /* optimization: list2 is a tail of list1, and so we
- are done, unless the application has a weird test function. */
- if (list1 == list2) {
- break;
- } else {
- val item = car(list2);
- val list2_key = funcall1(keyfun, item);
+ while (seq_get(&si1, &el1))
+ ptail = list_collect(ptail, el1);
- if (!member(list2_key, list1, testfun, keyfun))
- ptail = list_collect(ptail, item);
- }
+ while (seq_get(&si2, &el2)) {
+ val el2_key = funcall1(keyfun, el2);
+
+ if (!member(el2_key, out, testfun, keyfun))
+ ptail = list_collect(ptail, el2);
}
- return make_like(out, list_orig);
+ return make_like(out, seq1);
}
val copy(val seq)
diff --git a/lib.h b/lib.h
index 6d706b3d..08e7acb2 100644
--- a/lib.h
+++ b/lib.h
@@ -1078,6 +1078,7 @@ val drop_while(val pred, val seq, val keyfun);
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 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 658fbad0..396019b1 100644
--- a/txr.1
+++ b/txr.1
@@ -28728,13 +28728,27 @@ and
returning a new sequence: the union sequence,
intersection sequence and difference sequence.
-The sequences
+The arguments
.meta seq1
and
.meta seq2
-need not be of the same kind.
+need not be of the same kind. They may be hash tables.
+
The returned sequence is of the same kind as
.metn seq1 .
+If
+.meta seq1
+is a hash table, the returned sequence is a list.
+
+For the purposes of these functions, an input which is a hash table
+is considered as if it were a sequence of hash key and hash
+value pairs represented as cons cells, the
+.code car
+slots of which are the hash keys, and the
+.code cdr
+of which are the hash values. This means that if no
+.meta keyfun
+is specified, these pairs are taken as keys.
Since the input sequences are defined as representing sets, they are assumed
not to contain duplicate elements. These functions are not required, but may,
@@ -28812,7 +28826,7 @@ then the
.code equal
function is used.
-Note: a function identical to
+Note: a function similar to
.code diff
named
.code set-diff
@@ -28830,6 +28844,25 @@ function, but is
honored by the implementation for at as long as the
.code set-diff
synonym continues to be available.
+The
+.code set-diff
+function doesn't support hash tables and is inefficient for vectors and
+strings.
+
+Note: these functions are not efficient for the processing of hash tables,
+even when both inputs are hashes, the
+.meta keyfun
+argument is
+.codn car ,
+and
+.meta testfun
+matches the equality used by both hash table inputs.
+If applicable, the operations
+.codn hash-uni ,
+.code hash-isec
+and
+.code hash-diff
+should be used instead.
.coNP Functions @, mapcar @, mappend @ mapcar* and @ mappend*
.synb