hyperformula
Version:
HyperFormula is a JavaScript engine for efficient processing of spreadsheet-like data and formulas
81 lines (79 loc) • 3.51 kB
JavaScript
;
exports.__esModule = true;
exports.AdvancedFind = void 0;
var _InterpreterValue = require("../interpreter/InterpreterValue");
var _ArithmeticHelper = require("../interpreter/ArithmeticHelper");
var _binarySearch = require("../interpreter/binarySearch");
/**
* @license
* Copyright (c) 2025 Handsoncode. All rights reserved.
*/
const NOT_FOUND = -1;
class AdvancedFind {
constructor(dependencyGraph) {
this.dependencyGraph = dependencyGraph;
}
advancedFind(keyMatcher, rangeValue, {
returnOccurrence
} = {
returnOccurrence: 'first'
}) {
const range = rangeValue.range;
const values = range === undefined ? rangeValue.valuesFromTopLeftCorner() : this.dependencyGraph.computeListOfValuesInRange(range);
const initialIterationIndex = returnOccurrence === 'first' ? 0 : values.length - 1;
const iterationCondition = returnOccurrence === 'first' ? i => i < values.length : i => i >= 0;
const incrementIndex = returnOccurrence === 'first' ? i => i + 1 : i => i - 1;
for (let i = initialIterationIndex; iterationCondition(i); i = incrementIndex(i)) {
if (keyMatcher((0, _InterpreterValue.getRawValue)(values[i]))) {
return i;
}
}
return NOT_FOUND;
}
basicFind(searchKey, rangeValue, searchCoordinate, {
ordering,
ifNoMatch,
returnOccurrence
}) {
const normalizedSearchKey = typeof searchKey === 'string' ? (0, _ArithmeticHelper.forceNormalizeString)(searchKey) : searchKey;
const range = rangeValue.range;
if (range === undefined) {
return this.findNormalizedValue(normalizedSearchKey, rangeValue.valuesFromTopLeftCorner(), ifNoMatch, returnOccurrence);
}
if (ordering === 'none') {
return this.findNormalizedValue(normalizedSearchKey, this.dependencyGraph.computeListOfValuesInRange(range), ifNoMatch, returnOccurrence);
}
return (0, _binarySearch.findLastOccurrenceInOrderedRange)(normalizedSearchKey, range, {
searchCoordinate,
orderingDirection: ordering,
ifNoMatch
}, this.dependencyGraph);
}
findNormalizedValue(searchKey, searchArray, ifNoMatch = 'returnNotFound', returnOccurrence = 'first') {
const normalizedArray = searchArray.map(_InterpreterValue.getRawValue).map(val => typeof val === 'string' ? (0, _ArithmeticHelper.forceNormalizeString)(val) : val);
if (ifNoMatch === 'returnNotFound') {
return returnOccurrence === 'first' ? normalizedArray.indexOf(searchKey) : normalizedArray.lastIndexOf(searchKey);
}
const compareFn = ifNoMatch === 'returnLowerBound' ? (left, right) => (0, _binarySearch.compare)(left, right) : (left, right) => -(0, _binarySearch.compare)(left, right);
let bestValue = ifNoMatch === 'returnLowerBound' ? -Infinity : Infinity;
let bestIndex = NOT_FOUND;
const initialIterationIndex = returnOccurrence === 'first' ? 0 : normalizedArray.length - 1;
const iterationCondition = returnOccurrence === 'first' ? i => i < normalizedArray.length : i => i >= 0;
const incrementIndex = returnOccurrence === 'first' ? i => i + 1 : i => i - 1;
for (let i = initialIterationIndex; iterationCondition(i); i = incrementIndex(i)) {
const value = normalizedArray[i];
if (value === searchKey) {
return i;
}
if (compareFn(value, searchKey) > 0) {
continue;
}
if (compareFn(bestValue, value) < 0) {
bestValue = value;
bestIndex = i;
}
}
return bestIndex;
}
}
exports.AdvancedFind = AdvancedFind;