mirror of
https://github.com/ONLYOFFICE/sdkjs.git
synced 2026-02-10 18:15:19 +08:00
[SE] optimize CountIfCache.prototype._calculate. Implemented storage and search in simple data types
This commit is contained in:
@ -12063,10 +12063,16 @@ function (window, undefined) {
|
||||
this.cacheRanges = {};
|
||||
}
|
||||
CountIfCache.prototype.constructor = CountIfCache;
|
||||
/**
|
||||
* Extracts and categorizes all values from a range into a universal array structure
|
||||
* @private
|
||||
* @param {cArea} range - The range object to extract values from
|
||||
* @returns {Object.<cElementType, Array|number>} Object where keys are cElementType constants and values are arrays of cell values or count for empty cells
|
||||
*/
|
||||
CountIfCache.prototype._getUniversalArrayFromRange = function(range) {
|
||||
const res = {};
|
||||
const bbox = range.getBBox0();
|
||||
let emptyCount = (Math.abs(bbox.c1 - bbox.c2) + 1) * (Math.abs(bbox.r1 - bbox.r2) + 1);
|
||||
let emptyCount = (bbox.c2 - bbox.c1 + 1) * (bbox.r2 - bbox.r1 + 1);
|
||||
range.foreach2(function(cell) {
|
||||
const type = cell.type;
|
||||
if (type !== cElementType.empty) {
|
||||
@ -12075,7 +12081,9 @@ function (window, undefined) {
|
||||
}
|
||||
let value = cell;
|
||||
if (type === cElementType.error) {
|
||||
value = new AscCommonExcel.cNumber(cell.errorType);
|
||||
value = cell.errorType;
|
||||
} else {
|
||||
value = value.value;
|
||||
}
|
||||
res[type].push(value);
|
||||
}
|
||||
@ -12083,26 +12091,7 @@ function (window, undefined) {
|
||||
for (let i in res) {
|
||||
emptyCount -= res[i].length;
|
||||
}
|
||||
res[cElementType.empty] = emptyCount
|
||||
return res;
|
||||
};
|
||||
CountIfCache.prototype._getUniversalArrayFromArray = function(array) {
|
||||
const res = {};
|
||||
array.foreach(function(cell) {
|
||||
const type = cell.type;
|
||||
if (!res[type]) {
|
||||
if (type === cElementType.empty) {
|
||||
res[type] = 0;
|
||||
} else {
|
||||
res[type] = [];
|
||||
}
|
||||
}
|
||||
let value = cell;
|
||||
if (type === cElementType.error) {
|
||||
value = new AscCommonExcel.cNumber(cell.errorType);
|
||||
}
|
||||
type === cElementType.empty ? res[type] += 1 : res[type].push(value);
|
||||
});
|
||||
res[cElementType.empty] = emptyCount;
|
||||
return res;
|
||||
};
|
||||
CountIfCache.prototype.calculate = function (arg, _arg1) {
|
||||
@ -12123,19 +12112,15 @@ function (window, undefined) {
|
||||
} else if (cElementType.cell === arg1.type || cElementType.cell3D === arg1.type) {
|
||||
arg1 = arg1.getValue();
|
||||
}
|
||||
|
||||
if (cElementType.array === arg0.type) {
|
||||
const uArray = this._getUniversalArrayFromArray(arg0)
|
||||
return this._calculate(uArray, arg1);
|
||||
} else if (cElementType.cell === arg0.type || cElementType.cell3D === arg0.type) {
|
||||
if (cElementType.cell === arg0.type || cElementType.cell3D === arg0.type) {
|
||||
const arr = {};
|
||||
const value = arg0.getValue();
|
||||
if (value.type === cElementType.empty) {
|
||||
arr[value.type] = 1;
|
||||
} else if (value.type === cElementType.error) {
|
||||
arr[value.type] = [new cNumber(value.errorType)];
|
||||
arr[value.type] = [value.errorType];
|
||||
} else {
|
||||
arr[value.type] = [value];
|
||||
arr[value.type] = [value.value];
|
||||
}
|
||||
return this._calculate(arr, arg1);
|
||||
} else if (cElementType.cellsRange === arg0.type || cElementType.cellsRange3D === arg0.type) {
|
||||
@ -12167,15 +12152,86 @@ function (window, undefined) {
|
||||
}
|
||||
return res;
|
||||
};
|
||||
/**
|
||||
* @private
|
||||
* @param {cElementType} type
|
||||
* @param {string} op
|
||||
* @returns {Function}
|
||||
*/
|
||||
CountIfCache.prototype._getMatchingFunction = function(type, op) {
|
||||
if (type === cElementType.string) {
|
||||
switch(op) {
|
||||
case ">":
|
||||
return function (a, b) {
|
||||
return AscCommonExcel.stringCompare(a, b) > 0;
|
||||
};
|
||||
case "<":
|
||||
return function (a, b) {
|
||||
return AscCommonExcel.stringCompare(a, b) < 0;
|
||||
};
|
||||
case ">=":
|
||||
return function (a, b) {
|
||||
return AscCommonExcel.stringCompare(a, b) >= 0;
|
||||
};
|
||||
case "<=":
|
||||
return function (a, b) {
|
||||
return AscCommonExcel.stringCompare(a, b) <= 0;
|
||||
};
|
||||
case "<>":
|
||||
return function (a, b) {
|
||||
return !AscCommonExcel.searchRegExp2(a, b);
|
||||
};
|
||||
case "=":
|
||||
default:
|
||||
return function (a, b) {
|
||||
return AscCommonExcel.searchRegExp2(a, b);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
switch(op) {
|
||||
case ">":
|
||||
return function (a, b) {
|
||||
return a > b;
|
||||
};
|
||||
case "<":
|
||||
return function (a, b) {
|
||||
return a < b;
|
||||
};
|
||||
case ">=":
|
||||
return function (a, b) {
|
||||
return a >= b;
|
||||
};
|
||||
case "<=":
|
||||
return function (a, b) {
|
||||
return a <= b;
|
||||
};
|
||||
case "<>":
|
||||
return function (a, b) {
|
||||
return a !== b;
|
||||
};
|
||||
case "=":
|
||||
default:
|
||||
return function (a, b) {
|
||||
return a === b;
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
CountIfCache.prototype._calculate = function (arr, arg1) {
|
||||
let _count = 0;
|
||||
let matchingInfo = AscCommonExcel.matchingValue(arg1);
|
||||
let type = matchingInfo.val.type;
|
||||
if (matchingInfo.val.type === cElementType.string) {
|
||||
let searchValue = matchingInfo.val;
|
||||
if (type === cElementType.string) {
|
||||
searchValue = searchValue.toString().toLowerCase();
|
||||
} else {
|
||||
searchValue = searchValue.value;
|
||||
}
|
||||
if (type === cElementType.string) {
|
||||
const checkErr = new cError(matchingInfo.val.value.toUpperCase());
|
||||
if (checkErr.errorType !== -1) {
|
||||
type = cElementType.error;
|
||||
matchingInfo.val = new cNumber(checkErr.errorType);
|
||||
searchValue = checkErr.errorType;
|
||||
}
|
||||
}
|
||||
if (matchingInfo.op === "<>") {
|
||||
@ -12186,15 +12242,16 @@ function (window, undefined) {
|
||||
}
|
||||
}
|
||||
const typedArr = arr[type];
|
||||
if (matchingInfo.val.value === "" && matchingInfo.op !== "<>") {
|
||||
if (searchValue === "" && matchingInfo.op !== "<>") {
|
||||
if (arr[cElementType.empty]) {
|
||||
return new cNumber(arr[cElementType.empty]);
|
||||
}
|
||||
return new cNumber(0);
|
||||
}
|
||||
const matchingFunction = this._getMatchingFunction(type, matchingInfo.op);
|
||||
if (typedArr) {
|
||||
for (let i = 0; i < typedArr.length; i += 1) {
|
||||
_count += matching(typedArr[i], matchingInfo, true, true);
|
||||
_count += matchingFunction(typedArr[i], searchValue);
|
||||
}
|
||||
}
|
||||
return new cNumber(_count);
|
||||
|
||||
@ -19221,21 +19221,6 @@ $(function () {
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 0);
|
||||
|
||||
// Case #29: Array, String. Count values greater than 1 in horizontal array
|
||||
oParser = new parserFormula('COUNTIF({1,2,3},">1")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 2); // ms - doesn't work, gs - 2, lo - 2
|
||||
|
||||
// Case #30: Array, String. Count values greater than 1 in vertical array
|
||||
oParser = new parserFormula('COUNTIF({1;2;3},">1")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 2); // ms - doesn't work, gs - 2, lo - 2
|
||||
|
||||
// Case #31: Array, String. Count values greater than 1 in 2D array
|
||||
oParser = new parserFormula('COUNTIF({1,2,3;4,5,6},">1")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 5); // ms - doesn't work, gs - 5, lo - 5
|
||||
|
||||
ws.getRange2("A100").setValue("Math");
|
||||
ws.getRange2("A101").setValue("87");
|
||||
ws.getRange2("A102").setValue("99");
|
||||
@ -19259,36 +19244,6 @@ $(function () {
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 1);
|
||||
|
||||
// Case #34: Array, String. Count exact matches in mixed array
|
||||
oParser = new parserFormula('COUNTIF({10,20,10,30,10},"10")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 3);
|
||||
|
||||
// Case #35: Array, String. Count text matches in string array
|
||||
oParser = new parserFormula('COUNTIF({"apple","banana","apple","cherry"},"apple")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 2);
|
||||
|
||||
// Case #36: Array, String. Count values less than threshold in numeric array
|
||||
oParser = new parserFormula('COUNTIF({5,15,25,"0",45},"<20")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 2);
|
||||
|
||||
// Case #37: Array, Boolean. Count TRUE values in boolean array
|
||||
oParser = new parserFormula('COUNTIF({TRUE,1,TRUE,TRUE,FALSE},TRUE)', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 3);
|
||||
|
||||
// Case #38: Array, String. Count wildcard matches in text array
|
||||
oParser = new parserFormula('COUNTIF({"test","testing","best","rest"},"*est")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 3);
|
||||
|
||||
// Case #39: Array, String. Count not equal values in mixed array
|
||||
oParser = new parserFormula('COUNTIF({"as",2,3,2,"4"},"<>2")', "C2", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 3);
|
||||
|
||||
ws.getRange2("A200").setValue("");
|
||||
ws.getRange2("A201").setValue("123");
|
||||
ws.getRange2("A202").setValue("");
|
||||
@ -19372,12 +19327,7 @@ $(function () {
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 2);
|
||||
|
||||
// Case #5: Array, String. Count errors in mixed error array
|
||||
oParser = new parserFormula('COUNTIF({#N/A,#DIV/0!,#VALUE!,#REF!},"<#N/A")', "AC5", ws);
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 3);
|
||||
|
||||
// Case #6: Area, String. Count values greater than error boundary
|
||||
// Case #5: Area, String. Count values greater than error boundary
|
||||
ws.getRange2("AD1").setValue("#N/A");
|
||||
ws.getRange2("AD2").setValue("10");
|
||||
ws.getRange2("AD3").setValue("20");
|
||||
@ -19386,7 +19336,7 @@ $(function () {
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 0);
|
||||
|
||||
// Case #7: Area, String. Count specific error type in mixed range
|
||||
// Case #6: Area, String. Count specific error type in mixed range
|
||||
ws.getRange2("AE1").setValue("#N/A");
|
||||
ws.getRange2("AE2").setValue("#DIV/0!");
|
||||
ws.getRange2("AE3").setValue("#N/A");
|
||||
@ -19395,7 +19345,7 @@ $(function () {
|
||||
assert.ok(oParser.parse());
|
||||
assert.strictEqual(oParser.calculate().getValue(), 2);
|
||||
|
||||
// Case #8: Area, String. Count specific error type in mixed range
|
||||
// Case #7: Area, String. Count specific error type in mixed range
|
||||
ws.getRange2("AF1").setValue("#VALUE!");
|
||||
ws.getRange2("AF2").setValue("#DIV/0!");
|
||||
ws.getRange2("AF3").setValue("#VALUE!");
|
||||
|
||||
Reference in New Issue
Block a user