spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[RANK.AVG] formula added and tested
author
Ben Vogt <[email protected]>
date
2017-07-30 12:20:25
stats
8 file(s) changed, 132 insertions(+), 8 deletions(-)
files
DOCS.md
TODO.md
dist/Formulas/AllFormulas.js
dist/Formulas/Statistical.js
src/Formulas/AllFormulas.ts
src/Formulas/Statistical.ts
tests/Formulas/StatisticalTest.ts
tests/SheetFormulaTest.ts
  1diff --git a/DOCS.md b/DOCS.md
  2index 66067ae..9effb9c 100644
  3--- a/DOCS.md
  4+++ b/DOCS.md
  5@@ -2090,6 +2090,17 @@
  6 @returns {number} 
  7 @constructor
  8 ```
  9+
 10+### AVG 
 11+
 12+```
 13+  Returns the position of a given entry in the entire list, measured either from top to bottom or bottom to top. If more than one value exists in the same data-set, the average range of the values will be returned. 
 14+@param value - Value to find the rank of. 
 15+@param data - Values or range of the data-set. 
 16+@param isAscending - [OPTIONAL] The type of rank: 0 to rank from the highest, 1 to rank from the lowest. Defaults to 0. 
 17+@returns {number} 
 18+@constructor
 19+```
 20 ## Text
 21 
 22 
 23diff --git a/TODO.md b/TODO.md
 24index a1bf6b5..9cc3342 100644
 25--- a/TODO.md
 26+++ b/TODO.md
 27@@ -65,7 +65,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
 28 * HYPGEOMDIST
 29 * LOGINV
 30 * LOGNORMDIST
 31-* RANK.AVG
 32 * RANK.EQ
 33 * T.INV
 34 * T.INV.2T
 35diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
 36index 90b6b95..6b9608d 100644
 37--- a/dist/Formulas/AllFormulas.js
 38+++ b/dist/Formulas/AllFormulas.js
 39@@ -194,6 +194,7 @@ exports.STEYX = Statistical_1.STEYX;
 40 exports.PROB = Statistical_1.PROB;
 41 exports.MODE = Statistical_1.MODE;
 42 exports.RANK = Statistical_1.RANK;
 43+exports.RANK$AVG = Statistical_1.RANK$AVG;
 44 var Text_1 = require("./Text");
 45 exports.ARABIC = Text_1.ARABIC;
 46 exports.CHAR = Text_1.CHAR;
 47@@ -238,6 +239,7 @@ var __COMPLEX = {
 48     "POISSON.DIST": Statistical_1.POISSON,
 49     "PERCENTRANK.INC": Statistical_1.PERCENTRANK,
 50     "PERCENTRANK.EXC": Statistical_1.PERCENTRANK$EXC,
 51-    "ERROR.TYPE": Info_1.ERRORTYPE
 52+    "ERROR.TYPE": Info_1.ERRORTYPE,
 53+    "RANK.AVG": Statistical_1.RANK$AVG
 54 };
 55 exports.__COMPLEX = __COMPLEX;
 56diff --git a/dist/Formulas/Statistical.js b/dist/Formulas/Statistical.js
 57index b8b1cef..ec2d588 100644
 58--- a/dist/Formulas/Statistical.js
 59+++ b/dist/Formulas/Statistical.js
 60@@ -1889,3 +1889,41 @@ var RANK = function (value, data, isAscending) {
 61     return range.indexOf(value) + 1;
 62 };
 63 exports.RANK = RANK;
 64+/**
 65+ * Returns the position of a given entry in the entire list, measured either from top to bottom or bottom to top. If
 66+ * more than one value exists in the same data-set, the average range of the values will be returned.
 67+ * @param value - Value to find the rank of.
 68+ * @param data - Values or range of the data-set.
 69+ * @param isAscending - [OPTIONAL] The type of rank: 0 to rank from the highest, 1 to rank from the lowest. Defaults to
 70+ * 0.
 71+ * @returns {number}
 72+ * @constructor
 73+ */
 74+var RANK$AVG = function (value, data, isAscending) {
 75+    ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 2, 3, "RANK.AVG");
 76+    value = TypeConverter_1.TypeConverter.firstValueAsNumber(value);
 77+    var range = Filter_1.Filter.flattenAndThrow(data).map(TypeConverter_1.TypeConverter.valueToNumber);
 78+    function _countIn(range, value) {
 79+        var result = 0;
 80+        for (var i = 0; i < range.length; i++) {
 81+            if (range[i] === value) {
 82+                result++;
 83+            }
 84+        }
 85+        return result;
 86+    }
 87+    isAscending = (typeof isAscending === 'undefined') ? false : isAscending;
 88+    var sort = (isAscending) ? function (a, b) {
 89+        return a - b;
 90+    } : function (a, b) {
 91+        return b - a;
 92+    };
 93+    range = range.sort(sort);
 94+    var rangeIndex = range.indexOf(value);
 95+    if (rangeIndex === -1) {
 96+        throw new Errors_1.NAError("RANK.AVG can't produce a result because parameter 1 is not in the dataset.");
 97+    }
 98+    var count = _countIn(range, value);
 99+    return (count > 1) ? (2 * rangeIndex + count + 1) / 2 : rangeIndex + 1;
100+};
101+exports.RANK$AVG = RANK$AVG;
102diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
103index fbffeff..9337b08 100644
104--- a/src/Formulas/AllFormulas.ts
105+++ b/src/Formulas/AllFormulas.ts
106@@ -199,7 +199,8 @@ import {
107   STEYX,
108   PROB,
109   MODE,
110-  RANK
111+  RANK,
112+  RANK$AVG
113 } from "./Statistical";
114 import {
115   ARABIC,
116@@ -248,7 +249,8 @@ var __COMPLEX = {
117   "POISSON.DIST": POISSON,
118   "PERCENTRANK.INC": PERCENTRANK,
119   "PERCENTRANK.EXC": PERCENTRANK$EXC,
120-  "ERROR.TYPE": ERRORTYPE
121+  "ERROR.TYPE": ERRORTYPE,
122+  "RANK.AVG": RANK$AVG
123 };
124 
125 export {
126@@ -473,5 +475,6 @@ export {
127   STEYX,
128   PROB,
129   MODE,
130-  RANK
131+  RANK,
132+  RANK$AVG
133 }
134\ No newline at end of file
135diff --git a/src/Formulas/Statistical.ts b/src/Formulas/Statistical.ts
136index 5b12993..6a55a42 100644
137--- a/src/Formulas/Statistical.ts
138+++ b/src/Formulas/Statistical.ts
139@@ -1870,6 +1870,47 @@ var RANK = function (value, data, isAscending?) {
140 };
141 
142 
143+/**
144+ * Returns the position of a given entry in the entire list, measured either from top to bottom or bottom to top. If
145+ * more than one value exists in the same data-set, the average range of the values will be returned.
146+ * @param value - Value to find the rank of.
147+ * @param data - Values or range of the data-set.
148+ * @param isAscending - [OPTIONAL] The type of rank: 0 to rank from the highest, 1 to rank from the lowest. Defaults to
149+ * 0.
150+ * @returns {number}
151+ * @constructor
152+ */
153+var RANK$AVG =  function (value, data, isAscending?) {
154+  ArgsChecker.checkLengthWithin(arguments, 2, 3, "RANK.AVG");
155+  value = TypeConverter.firstValueAsNumber(value);
156+  var range = Filter.flattenAndThrow(data).map(TypeConverter.valueToNumber)
157+
158+  function _countIn(range, value) {
159+    var result = 0;
160+    for (var i = 0; i < range.length; i++) {
161+      if (range[i] === value) {
162+        result++;
163+      }
164+    }
165+    return result;
166+  }
167+
168+  isAscending = (typeof isAscending === 'undefined') ? false : isAscending;
169+  var sort = (isAscending) ? function (a, b) {
170+    return a - b;
171+  } : function (a, b) {
172+    return b - a;
173+  };
174+  range = range.sort(sort);
175+  var rangeIndex = range.indexOf(value);
176+  if (rangeIndex === -1) {
177+    throw new NAError("RANK.AVG can't produce a result because parameter 1 is not in the dataset.");
178+  }
179+  var count = _countIn(range, value);
180+  return (count > 1) ? (2 * rangeIndex + count + 1) / 2 : rangeIndex + 1;
181+};
182+
183+
184 export {
185   AVERAGE,
186   AVERAGEA,
187@@ -1928,5 +1969,6 @@ export {
188   STEYX,
189   PROB,
190   MODE,
191-  RANK
192+  RANK,
193+  RANK$AVG
194 }
195\ No newline at end of file
196diff --git a/tests/Formulas/StatisticalTest.ts b/tests/Formulas/StatisticalTest.ts
197index d11c21a..b0e1836 100644
198--- a/tests/Formulas/StatisticalTest.ts
199+++ b/tests/Formulas/StatisticalTest.ts
200@@ -56,7 +56,8 @@ import {
201   STEYX,
202   PROB,
203   MODE,
204-  RANK
205+  RANK,
206+  RANK$AVG
207 } from "../../src/Formulas/Statistical";
208 import * as ERRORS from "../../src/Errors";
209 import {
210@@ -1133,6 +1134,8 @@ test("MODE", function() {
211 
212 test("RANK", function() {
213   assertEquals(RANK(2, [1, 2, 3, 4, 5, 6, 7, 8, 9], true), 2);
214+  assertEquals(RANK(3, [1, 3, 4, 5, 6, 7, 8, 9]), 7);
215+  assertEquals(RANK(3, [1, 3, 4, 5, 6, 7, 8, 9], true), 2);
216   assertEquals(RANK(2, [7, 1, 2, 4, 100, 8, 9], true), 2);
217   catchAndAssertEquals(function() {
218     RANK(44, [7, 1]);
219@@ -1143,4 +1146,23 @@ test("RANK", function() {
220   catchAndAssertEquals(function() {
221     RANK.apply(this, [44, [7, 1], true, false]);
222   }, ERRORS.NA_ERROR);
223+});
224+
225+test("RANK.AVG", function() {
226+  assertEquals(RANK$AVG(2, [1, 2, 2, 3, 4, 5, 6, 7, 8, 9], true), 2.5);
227+  assertEquals(RANK$AVG(2, [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]), 8.5);
228+  assertEquals(RANK$AVG(2, [2]), 1);
229+  assertEquals(RANK$AVG(2, [1, 2, 3, 4, 5, 6, 7, 8, 9], true), 2);
230+  assertEquals(RANK$AVG(3, [1, 3, 4, 5, 6, 7, 8, 9]), 7);
231+  assertEquals(RANK$AVG(3, [1, 3, 4, 5, 6, 7, 8, 9], true), 2);
232+  assertEquals(RANK$AVG(2, [7, 1, 2, 4, 100, 8, 9], true), 2);
233+  catchAndAssertEquals(function() {
234+    RANK$AVG(44, [7, 1]);
235+  }, ERRORS.NA_ERROR);
236+  catchAndAssertEquals(function() {
237+    RANK$AVG.apply(this, [44]);
238+  }, ERRORS.NA_ERROR);
239+  catchAndAssertEquals(function() {
240+    RANK$AVG.apply(this, [44, [7, 1], true, false]);
241+  }, ERRORS.NA_ERROR);
242 });
243\ No newline at end of file
244diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
245index cda030d..99cce03 100644
246--- a/tests/SheetFormulaTest.ts
247+++ b/tests/SheetFormulaTest.ts
248@@ -934,6 +934,11 @@ test("Sheet RANK", function(){
249   assertFormulaEquals('=RANK([2], [1, 2, 3, 4, 5, 6, 7, 8, 9], true)', 2);
250 });
251 
252+test("Sheet RANK.AVG", function(){
253+  assertFormulaEquals('=RANK.AVG([2], [1, 2, 3, 4, 5, 6, 7, 8, 9], true)', 2);
254+});
255+
256+
257 test("Sheet *", function(){
258   assertFormulaEquals('= 10 * 10', 100);
259   assertFormulaEquals('= 10 * 0', 0);