summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-03-02 21:10:36 -0800
committerKaz Kylheku <kaz@kylheku.com>2022-03-02 21:10:36 -0800
commit782873797401693035c47040f43bdb82630c45fa (patch)
tree897c38804bfd84519f228fa4a8258f8c4b9d0f51
parent9175dc378d5b2a6da0810d17407c3decfa91206a (diff)
downloadtxr-782873797401693035c47040f43bdb82630c45fa.tar.gz
txr-782873797401693035c47040f43bdb82630c45fa.tar.bz2
txr-782873797401693035c47040f43bdb82630c45fa.zip
New function: group-map.
* hash.c (group_map): New function. (hash_init): group-map intrinsic registered. * hash.h (group_map): Declared. * tests/010/hash.tl: New test case. * txr.1: Documented together with group-by. Extra paren removed from group-by example.
-rw-r--r--hash.c7
-rw-r--r--hash.h1
-rw-r--r--stdlib/doc-syms.tl3
-rw-r--r--tests/010/hash.tl4
-rw-r--r--txr.145
5 files changed, 51 insertions, 9 deletions
diff --git a/hash.c b/hash.c
index 352f3f33..70471382 100644
--- a/hash.c
+++ b/hash.c
@@ -1667,6 +1667,12 @@ val group_by(val func, val seq, struct args *hashv_args)
}
}
+val group_map(val by_fun, val filter_fun, val seq, struct args *hashv_args)
+{
+ val hash = group_by(by_fun, seq, hashv_args);
+ return hash_update(hash, filter_fun);
+}
+
val group_reduce(val hash, val by_fun, val reduce_fun, val seq,
val initval, val filter_fun)
{
@@ -2135,6 +2141,7 @@ void hash_init(void)
reg_fun(intern(lit("hash-subset"), user_package), func_n2(hash_subset));
reg_fun(intern(lit("hash-proper-subset"), user_package), func_n2(hash_proper_subset));
reg_fun(intern(lit("group-by"), user_package), func_n2v(group_by));
+ reg_fun(intern(lit("group-map"), user_package), func_n3v(group_map));
reg_fun(intern(lit("group-reduce"), user_package),
func_n6o(group_reduce, 4));
reg_fun(intern(lit("hash-update"), user_package), func_n2(hash_update));
diff --git a/hash.h b/hash.h
index 4310d3d1..bbc2c34b 100644
--- a/hash.h
+++ b/hash.h
@@ -85,6 +85,7 @@ val hash_from_alist_v(val alist, struct args *hashv_args);
val hash_list(val keys, struct args *hashv_args);
val hash_zip(val keys, val vals, struct args *hashv_args);
val group_by(val func, val seq, struct args *hashv_args);
+val group_map(val by_fun, val filter_fun, val seq, struct args *hashv_args);
val group_reduce(val hash, val by_fun, val reduce_fun, val seq,
val initval, val filter_fun);
val hash_keys(val hash);
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index 95092836..34e139b6 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -914,7 +914,8 @@
("grade" "N-00091853")
("greater" "N-02AC1F73")
("group" "N-03DE71BA")
- ("group-by" "N-02F6F229")
+ ("group-by" "N-02229668")
+ ("group-map" "N-02229668")
("group-reduce" "N-001A208F")
("gun" "N-0323BEBD")
("handle" "N-03F7D8B5")
diff --git a/tests/010/hash.tl b/tests/010/hash.tl
index bb006612..7f662b51 100644
--- a/tests/010/hash.tl
+++ b/tests/010/hash.tl
@@ -9,8 +9,8 @@
[group-by identity '(1 1 2 2 3 3 3)] #H(() (1 (1 1)) (2 (2 2)) (3 (3 3 3)))
(group-by (op mod @1 3) (range 0 10)) #H(() (0 (0 3 6 9))
(1 (1 4 7 10))
- (2 (2 5 8))))
-
+ (2 (2 5 8)))
+ [group-map (op mod @1 3) sum (range 0 10)] #H(() (0 18) (1 22) (2 15)))
(mtest
[group-reduce (hash) identity (do inc @1)
diff --git a/txr.1 b/txr.1
index 509b390a..f99e561b 100644
--- a/txr.1
+++ b/txr.1
@@ -53977,9 +53977,10 @@ with the value returned by
as the datum. This value
is also returned.
-.coNP Function @ group-by
+.coNP Functions @ group-by and @ group-map
.synb
-.mets (group-by < func < sequence << option *)
+.mets (group-by < by-fun < sequence << option *)
+.mets (group-map < by-fun < filter-fun < sequence << option *)
.syne
.desc
The
@@ -53992,7 +53993,7 @@ list or vector. Entries of the hash table are not elements of
but lists of elements of
.metn sequence .
The function
-.meta func
+.meta by-fun
is applied to
each element of
.meta sequence
@@ -54007,16 +54008,48 @@ if any, consist of the same keywords that are understood by the
.code hash
function, and determine the properties of the hash.
-.TP* Example:
+The
+.code group-map
+fun extends the semantics of
+.code group-by
+with a filtering step. It groups the elements of
+.meta sequence
+in exactly the same manner, using
+.metn by-fun .
+These lists of elements are then passed to
+.meta filter-fun
+whose return values become the values associated with the hash table keys.
+
+The effect of
+.code group-map
+may be obtained by a combination of
+.code group-by
+and
+.code hash-update
+according to the following equivalence:
+
+.verb
+ (group-map bf ff seq) <--> (let ((h (group-by bf seq)))
+ (hash-update h ff))
+.brev
+
+.TP* Examples:
Group the integers from 0 to 10 into three buckets keyed on 0, 1 and 2
according to the modulo 3 congruence:
.verb
- (group-by (op mod @1 3) (range 0 10)))
-
+ (group-by (op mod @1 3) (range 0 10))
-> #H(() (0 (0 3 6 9)) (1 (1 4 7 10)) (2 (2 5 8)))
.brev
+Same as above, but associate the keys with the sums of the
+buckets:
+
+.verb
+ [group-map (op mod @1 3) sum (range 0 10)]
+ -> #H(() (0 18) (1 22) (2 15))
+.brev
+
.coNP Function @ group-reduce
.synb
.mets (group-reduce < hash < classify-fun < binary-fun < seq