commit
message
Added Formula.COUNTIFS
author
Ben Vogt <[email protected]>
date
2017-02-15 02:58:27
stats
3 file(s) changed,
69 insertions(+),
2 deletions(-)
files
src/RawFormulas/RawFormulas.ts
src/RawFormulas/Utils.ts
tests/FormulasTest.ts
1diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
2index b5404e4..45fcb40 100644
3--- a/src/RawFormulas/RawFormulas.ts
4+++ b/src/RawFormulas/RawFormulas.ts
5@@ -80,7 +80,6 @@ var COMBIN = Formula["COMBIN"];
6 var CONCATENATE = Formula["CONCATENATE"];
7 var CONVERT = Formula["CONVERT"];
8 var CORREL = Formula["CORREL"];
9-var COUNTIFS = Formula["COUNTIFS"];
10 var COUNTUNIQUE = Formula["COUNTUNIQUE"];
11 var COVARIANCEP = Formula["COVARIANCEP"];
12 var COVARIANCES = Formula["COVARIANCES"];
13@@ -180,6 +179,39 @@ var COUNTIF = function (...values) {
14 return count;
15 };
16
17+var COUNTIFS = function (...values) {
18+ checkArgumentsAtLeastLength(values, 2);
19+ var criteriaEvaluationFunctions = values.map(function (criteria, index) {
20+ if (index % 2 === 1) {
21+ return CriteriaFunctionFactory.createCriteriaFunction(criteria);
22+ } else {
23+ return function () {return false;}
24+ }
25+ });
26+
27+ var count = 0;
28+ // For every value in the range
29+ for (var i = 0; i < values[0].length; i++) {
30+ // check for criteria eval for other ranges and other criteria pairs
31+ var otherCriteriaEvaluationSuccessfulSoFar = true;
32+ for (var x = 0; x < values.length; x += 2) {
33+ if (values[x].length < values[0].length) {
34+ throw new CellError(ERRORS.VALUE_ERROR, "Array arguments to COUNTIFS are of different size.");
35+ }
36+ var criteriaEvaluation = criteriaEvaluationFunctions[x+1];
37+ if (otherCriteriaEvaluationSuccessfulSoFar) {
38+ if (!criteriaEvaluation(values[x][i])) { // evaluate THIS value with x+1 index, which is criteria
39+ otherCriteriaEvaluationSuccessfulSoFar = false;
40+ }
41+ }
42+ }
43+ if (otherCriteriaEvaluationSuccessfulSoFar) {
44+ count++;
45+ }
46+ }
47+ return count;
48+};
49+
50 /**
51 * Returns the a count of the number of values in a dataset.
52 * @param values The values or ranges to consider when counting.
53diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
54index ae37b82..9ca22da 100644
55--- a/src/RawFormulas/Utils.ts
56+++ b/src/RawFormulas/Utils.ts
57@@ -231,7 +231,7 @@ class CriteriaFunctionFactory {
58 return false;
59 };
60
61- if (typeof criteria === "number") {
62+ if (typeof criteria === "number" || typeof criteria === "boolean") {
63 criteriaEvaluation = function (x) : boolean {
64 return x === criteria;
65 };
66diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
67index 162ab72..c0cffcc 100644
68--- a/tests/FormulasTest.ts
69+++ b/tests/FormulasTest.ts
70@@ -475,7 +475,41 @@ catchAndAssertEquals(function() {
71 }, ERRORS.NA_ERROR);
72
73
74-assertEquals(COUNTIFS([1, 5, 10], ">4", [1, 5, 10], ">4"), 2);
75+// Test COUNTIFS
76+// All COUNTIF tests should also work on COUNTIFS
77+assertEquals(COUNTIFS([1, 5, 10], ">4"), 2);
78+assertEquals(COUNTIFS([1, 2, 2, 2, 2, 2, 2, 2], ">1"), 7);
79+assertEquals(COUNTIFS([1, 5, 10], 5), 1);
80+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], 5), 4);
81+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], 10), 1);
82+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], ">5"), 1);
83+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "=5"), 4);
84+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "=10"), 1);
85+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "= 10 "), 1);
86+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], ">0"), 6);
87+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], ">=5"), 5);
88+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "<10"), 5);
89+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5, 44], "<=10"), 6);
90+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], ">4.99"), 5);
91+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "<4.99"), 1);
92+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "= 1.0.0 "), 0);
93+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "=>5"), 0);
94+assertEquals(COUNTIFS([1, 5, 5, 5, 10, 5], "==5"), 0);
95+assertEquals(COUNTIFS(["mom", "pop", "dad", "etc", "boom"], "*o*"), 3);
96+assertEquals(COUNTIFS(["mom", "pop", "dad", "etc", "mom"], "mom"), 2);
97+assertEquals(COUNTIFS(["mom", "pop", "dad", "etc", "mom"], "?o?"), 3);
98+assertEquals(COUNTIFS(["mom", "pop", "dad", "etc", "mom"], "???"), 5);
99+assertEquals(COUNTIFS(["mom", "pop", "dad", "etc", "mom"], "????"), 0);
100+assertEquals(COUNTIFS(["mom", "pop", "dad", "etc", "mom"], "?"), 0);
101+// Now actually test COUNTIFS
102+assertEquals(COUNTIFS([1, 5, 10, 20], ">4", [0, 0, 1, 1], "=1"), 2);
103+assertEquals(COUNTIFS([1, 5, 10, 20], ">4", [0, 0, 1, 1], "=1"), 2);
104+assertEquals(COUNTIFS([1, 5, 10, 20], ">4", [0, 0, 1, 1], "=1", [0, 0, 1, 1], "=1"), 2);
105+assertEquals(COUNTIFS([1, 5, 10, 20, 40], ">4", [0, 0, 1, 1, 1], "=1", [0, 0, 0, 0, 0], "=1"), 0);
106+assertEquals(COUNTIFS([1, 2, 3, 4], ">3", [true, true, false, true], true), 1);
107+catchAndAssertEquals(function() {
108+ COUNTIFS([1, 5, 10, 20], ">4", [0, 0], "=1");
109+}, ERRORS.VALUE_ERROR);
110
111 assertEquals(COUNTUNIQUE([1, 1, 10]), 2);
112