下面是一个非常简单的实用程序,可以正确模拟RANK
公式(包括升序和降序)。如果您需要使其按范围的另一列排序或使用另一个比较器,则很容易更改并使其更加通用。
您需要做的是按某些标准对目标列值的副本进行排序,获取结果索引,并将其递增,1
因为 Array 索引是0
基于 - 的。
/**
* @summary ranks a range by first column
* @param {number[][]} range
* @param {(1|0)} [ascending]
* @return {number[][]}
* @customfunction
*/
const rankRange = (values, ascending = 0) => {
try {
const rows = values.map(v => v).sort((a, b) => {
const aParsed = parseFloat(a[0]);
const bParsed = parseFloat(b[0]);
return ascending ?
aParsed - bParsed :
bParsed - aParsed;
});
return values.map((row) => {
return [rows.findIndex(r => r[0] === row[0]) + 1];
});
} catch (error) {
console.warn(`failed to rank column: ${error}`);
return [[]];
}
};
确保在您的项目中启用 V8 运行时以使其正常工作(或在使用前将其转换为 ES5 语法)。
性能说明 -map(v => v)
优先使用浅拷贝值。如果您预计项目数量会很高,请使用slice()
(感谢 TheMaster 的评论,我决定调查性能损失是什么)。运行下面的交互式代码片段以查看差异:
const rng = document.querySelector("input[type=range]");
const arr = [];
const bench = (func, lbl) => {
console.time(lbl);
func();
console.timeEnd(lbl);
}
rng.addEventListener("change", () => {
const {
value
} = rng;
const toAdd = new Array(+value).fill(42);
arr.length = 0;
arr.push( ...toAdd );
bench(() => arr.slice(), "slice");
bench(() => arr.map(v => v), "map");
});
.rng {
width: 100%
}
<input class="rng" type="range" min="1" max="1e5" step="1">