diff options
-rw-r--r-- | eval.c | 1 | ||||
-rw-r--r-- | lib.c | 25 | ||||
-rw-r--r-- | lib.h | 1 | ||||
-rw-r--r-- | stdlib/doc-syms.tl | 3 | ||||
-rw-r--r-- | tests/012/seq.tl | 10 | ||||
-rw-r--r-- | txr.1 | 74 |
6 files changed, 94 insertions, 20 deletions
@@ -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)); @@ -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); @@ -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)) @@ -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 |