summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eval.c1
-rw-r--r--lib.c25
-rw-r--r--lib.h1
-rw-r--r--stdlib/doc-syms.tl3
-rw-r--r--tests/012/seq.tl10
-rw-r--r--txr.174
6 files changed, 94 insertions, 20 deletions
diff --git a/eval.c b/eval.c
index 7f207de9..7fdc9627 100644
--- a/eval.c
+++ b/eval.c
@@ -7016,6 +7016,7 @@ void eval_init(void)
reg_fun(intern(lit("countql"), user_package), func_n2(countql));
reg_fun(intern(lit("countq"), user_package), func_n2(countq));
reg_fun(intern(lit("count-if"), user_package), func_n3o(count_if, 2));
+ reg_fun(intern(lit("count"), user_package), func_n4o(count, 2));
reg_fun(intern(lit("posqual"), user_package), func_n2(posqual));
reg_fun(intern(lit("rposqual"), user_package), func_n2(rposqual));
reg_fun(intern(lit("posql"), user_package), func_n2(posql));
diff --git a/lib.c b/lib.c
index cc0f923e..94e462ba 100644
--- a/lib.c
+++ b/lib.c
@@ -3373,6 +3373,31 @@ val count_if(val pred, val seq, val key_in)
plus(unum(count), ash(ocount, num_fast(CHAR_BIT * sizeof count))));
}
+val count(val item, val seq, val testfun_in, val keyfun_in)
+{
+ val self = lit("count");
+ val testfun = default_arg(testfun_in, equal_f);
+ val keyfun = default_arg(keyfun_in, identity_f);
+ seq_iter_t iter;
+ ucnum count = 0;
+ val ocount = zero;
+ val elem;
+
+ seq_iter_init(self, &iter, z(seq));
+
+ while (seq_get(&iter, &elem)) {
+ val subj = funcall1(keyfun, elem);
+ if (funcall2(testfun, item, subj))
+ if (++count == 0)
+ ocount = plus(ocount, one);
+ }
+
+ return if3(ocount == zero,
+ unum(count),
+ plus(unum(count), ash(ocount, num_fast(CHAR_BIT * sizeof count))));
+
+}
+
val some_satisfy(val seq, val pred_in, val key_in)
{
val pred = default_arg(pred_in, identity_f);
diff --git a/lib.h b/lib.h
index 89f17f52..4eab1198 100644
--- a/lib.h
+++ b/lib.h
@@ -724,6 +724,7 @@ val countqual(val obj, val list);
val countql(val obj, val list);
val countq(val obj, val list);
val count_if(val pred, val list, val key);
+val count(val item, val seq, val testfun_in, val keyfun_in);
val some_satisfy(val list, val pred, val key);
val all_satisfy(val list, val pred, val key);
val none_satisfy(val list, val pred, val key);
diff --git a/stdlib/doc-syms.tl b/stdlib/doc-syms.tl
index ba518652..4efb6391 100644
--- a/stdlib/doc-syms.tl
+++ b/stdlib/doc-syms.tl
@@ -404,7 +404,8 @@
("copy-vec" "N-010E7635")
("cos" "D-0021")
("cosh" "D-0081")
- ("count-if" "N-00BBC726")
+ ("count" "N-00AE0CB6")
+ ("count-if" "N-00AE0CB6")
("count-until-match" "N-00EFD668")
("countq" "N-01DF131F")
("countql" "N-01DF131F")
diff --git a/tests/012/seq.tl b/tests/012/seq.tl
index ae42a13e..71bdf5fd 100644
--- a/tests/012/seq.tl
+++ b/tests/012/seq.tl
@@ -489,3 +489,13 @@
[partition-if fn "a13cd9foo42z" 2] ("a13" "cd9" "foo42z")
[partition-if fn "a13cd9foo42z" 1] ("a13" "cd9foo42z")
[partition-if fn "a13cd9foo42z" 0] ("a13cd9foo42z"))
+
+(mtest
+ [count 1 nil] 0
+ [count 1 '(1 2 3 4 1 5)] 2
+ [count "abc" '("foo" "bar" "ABC" "abc" "def" "abc")] 2
+ [count "ABC" '("foo" "bar" "ABC" "abc" "def" "abc") : upcase-str] 3)
+
+(compile-only
+ (test
+ [count #1="abc" '("abc" "abc" "abc" #1# "abc" #1#" abc") eq] 2))
diff --git a/txr.1 b/txr.1
index 5823335a..cfd0c31f 100644
--- a/txr.1
+++ b/txr.1
@@ -34433,31 +34433,67 @@ to
.metn object ,
and return the count.
-.coNP Function @ count-if
+.coNP Functions @ count and @ count-if
.synb
-.mets (count-if < predicate-function < iterable <> [ key-function ])
+.mets (count < key < sequence >> [ testfun <> [ keyfun ]])
+.mets (count-if < predfun < iterable <> [ keyfun ])
.syne
.desc
The
+.code count
+and
.code count-if
-function counts the number of elements of
-.meta iterable
-which satisfy
-.meta predicate-function
-and returns the count.
+functions search through
+.meta sequence
+for items which match
+.metn key ,
+or satisfy the predicate function
+.metn predfun ,
+respectively. They return the number of matching or predicate-satisfying items.
-The optional
-.meta key-function
-specifies how each element from
-.meta iterable
-is transformed to an argument to
-.metn predicate-function .
-If this argument is omitted
-then the predicate function is applied to the elements directly, a behavior
-which is identical to
-.meta key-function
-being
-.codn "(fun identity)" .
+The
+.meta keyfun
+argument specifies a function which is applied to the elements
+of
+.meta sequence
+to produce the comparison key. If this argument is omitted,
+then the untransformed elements of
+.meta sequence
+are examined.
+
+The
+.code count
+function's
+.meta testfun
+argument specifies the test function which
+is used to compare the comparison keys from
+.meta sequence
+to
+.metn key .
+If this argument is omitted, then the
+.code equal
+function is used.
+The
+.code count
+function returns the number of elements of
+.meta sequence
+whose comparison key (as retrieved by
+.metn keyfun )
+matches the
+.meta key
+object, as compared by
+.metn testfun .
+
+The
+.code count-if
+function's
+.meta predfun
+argument specifies a predicate function
+which is applied to the successive comparison keys taken from
+.metn sequence .
+The function returns the count of the number keys for which
+.meta predfun
+returns true.
.coNP Functions @, posq @ posql and @ posqual
.synb