commit
message
Added Formulas.COUNTUNIQUE
author
Ben Vogt <[email protected]>
date
2017-02-18 21:54:54
stats
3 file(s) changed,
62 insertions(+),
3 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 1e075cb..4343863 100644
3--- a/src/RawFormulas/RawFormulas.ts
4+++ b/src/RawFormulas/RawFormulas.ts
5@@ -85,7 +85,8 @@ import {
6 CriteriaFunctionFactory,
7 ArgsChecker,
8 Filter,
9- TypeCaster
10+ TypeCaster,
11+ Serializer
12 } from "./Utils";
13 import {CellError, NUM_ERROR} from "../Errors"
14 import * as ERRORS from "../Errors"
15@@ -95,7 +96,6 @@ var ACCRINT = Formula["ACCRINT"];
16 var COMBIN = Formula["COMBIN"];
17 var CONVERT = Formula["CONVERT"];
18 var CORREL = Formula["CORREL"];
19-var COUNTUNIQUE = Formula["COUNTUNIQUE"];
20 var COVARIANCEP = Formula["COVARIANCEP"];
21 var COVARIANCES = Formula["COVARIANCES"];
22 var CUMIPMT = Formula["CUMIPMT"];
23@@ -132,6 +132,42 @@ var SUMX2MY2 = Formula["SUMX2MY2"];
24 var SUMX2PY2 = Formula["SUMX2PY2"];
25 var YEARFRAC = Formula["YEARFRAC"];
26
27+
28+/**
29+ * Counts the number of unique values in a list of specified values and ranges.
30+ * @param values The values or ranges to consider for uniqueness. Supports an arbitrary number of arguments for this
31+ * function.
32+ * @returns {number} of unique values passed in.
33+ * @constructor
34+ */
35+var COUNTUNIQUE = function (...values) : number {
36+ ArgsChecker.checkAtLeastLength(values, 1);
37+
38+ // Private function that will recursively generate an array of the unique primatives
39+ var countUniquePrivate = function (values: Array<any>) : Object {
40+ var uniques = {};
41+ for (var i = 0; i < values.length; i++) {
42+ if (Array.isArray(values[i])) {
43+ // For some reasons an empty range is converted to a range with a single empty string in it.
44+ if (values[i].length === 0) {
45+ values[i] = [""];
46+ }
47+ var uniquesOfArray = countUniquePrivate(values[i]);
48+ for (var key in uniquesOfArray) {
49+ uniques[key] = true;
50+ }
51+ } else {
52+ uniques[Serializer.serialize(values[i])] = true;
53+ }
54+ }
55+ return uniques;
56+ };
57+
58+ var uniques = countUniquePrivate(values);
59+ return Object.keys(uniques).length;
60+};
61+
62+
63 /**
64 * Calculates the sum of the products of corresponding entries in two equal-sized arrays or ranges.
65 * @param values Arrays or ranges whose entries will be multiplied with corresponding entries in the second such array
66diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
67index a135858..003b260 100644
68--- a/src/RawFormulas/Utils.ts
69+++ b/src/RawFormulas/Utils.ts
70@@ -351,12 +351,22 @@ class ArgsChecker {
71 throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ___. Expected 1 arguments, but got " + args.length + " arguments.");
72 }
73 }
74- }
75+}
76
77+/**
78+ * Class to hold static methods for serialization.
79+ */
80+class Serializer {
81+ static serialize(value: any) : string {
82+ var t = typeof value;
83+ return "<" + t + ": " + value + ">";
84+ }
85+}
86
87 export {
88 ArgsChecker,
89 CriteriaFunctionFactory,
90 Filter,
91+ Serializer,
92 TypeCaster
93 }
94\ No newline at end of file
95diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
96index 8a2341a..396d8c2 100644
97--- a/tests/FormulasTest.ts
98+++ b/tests/FormulasTest.ts
99@@ -635,7 +635,19 @@ catchAndAssertEquals(function() {
100 COUNTIFS([1, 5, 10, 20], ">4", [0, 0], "=1");
101 }, ERRORS.VALUE_ERROR);
102
103+// Test COUNTUNIQUE
104 assertEquals(COUNTUNIQUE([1, 1, 10]), 2);
105+assertEquals(COUNTUNIQUE(["1", 1, 10]), 3);
106+assertEquals(COUNTUNIQUE(["1", 1, 10, ""]), 4);
107+assertEquals(COUNTUNIQUE(["1", 1, 10, "", ""]), 4);
108+assertEquals(COUNTUNIQUE(["1", 1, 10, "", " "]), 5);
109+assertEquals(COUNTUNIQUE(["1", 1, 10, []]), 4);
110+assertEquals(COUNTUNIQUE(["", " ", [""], []]), 2);
111+assertEquals(COUNTUNIQUE([[""], []]), 1);
112+catchAndAssertEquals(function() {
113+ COUNTUNIQUE();
114+}, ERRORS.NA_ERROR);
115+
116
117 assertEquals(COVARIANCEP([3,2,4,5,6], [9,7,12,15,17]), 5.2);
118