perf(grid): scan all-null columns once
This commit is contained in:
1 parent
67df8be6d9
commit
48dc2dee88
2 files changed
+32
-1
No files matched your search
@@ -53,7 +53,22 @@ export function invertedHiddenColumnIndexes(availableIndexes: number[], hiddenIn
|
|||||||
|
|
||||||
export function allNullColumnIndexes(rows: ReadonlyArray<ReadonlyArray<unknown>>, availableIndexes: number[]): number[] {
|
export function allNullColumnIndexes(rows: ReadonlyArray<ReadonlyArray<unknown>>, availableIndexes: number[]): number[] {
|
||||||
if (rows.length === 0) return [];
|
if (rows.length === 0) return [];
|
||||||
return availableIndexes.filter((index) => rows.every((row) => row[index] === null));
|
// 单遍行扫描 + 候选原地压缩:列一旦见到非 null 即永久剔除,候选清空提前
|
||||||
|
// 返回。最坏复杂度同为 O(列×行)(全 null 时无法避免),改进在于常数项:
|
||||||
|
// 原实现逐列 rows.every 各自从头扫外层 rows 并逐格调用回调,这里每个
|
||||||
|
// 单元格至多访问一次且无闭包调用
|
||||||
|
const candidates = [...availableIndexes];
|
||||||
|
let count = candidates.length;
|
||||||
|
for (const row of rows) {
|
||||||
|
let write = 0;
|
||||||
|
for (let read = 0; read < count; read++) {
|
||||||
|
if (row[candidates[read]!] === null) candidates[write++] = candidates[read]!;
|
||||||
|
}
|
||||||
|
count = write;
|
||||||
|
if (count === 0) return [];
|
||||||
|
}
|
||||||
|
candidates.length = count;
|
||||||
|
return candidates;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hiddenColumnIndexesWithAllNullColumns(options: { availableIndexes: number[]; hiddenIndexes: ReadonlySet<number>; allNullIndexes: ReadonlySet<number> }): { hiddenIndexes: Set<number>; autoHiddenIndexes: Set<number> } {
|
export function hiddenColumnIndexesWithAllNullColumns(options: { availableIndexes: number[]; hiddenIndexes: ReadonlySet<number>; allNullIndexes: ReadonlySet<number> }): { hiddenIndexes: Set<number>; autoHiddenIndexes: Set<number> } {
|
||||||
|
|||||||
@@ -97,6 +97,22 @@ test("finds columns where every row is NULL", () => {
|
|||||||
assert.deepEqual(indexes, [1, 2]);
|
assert.deepEqual(indexes, [1, 2]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("all-null scan handles sparse, ragged and non-candidate columns", () => {
|
||||||
|
// 前缀多 null 但尾行非 null 的列必须被剔除;availableIndexes 之外的列不参与
|
||||||
|
const rows = [
|
||||||
|
[null, 1, null, null],
|
||||||
|
[null, null, null, null],
|
||||||
|
[null, null, 2, null],
|
||||||
|
];
|
||||||
|
assert.deepEqual(allNullColumnIndexes(rows, [0, 1, 2]), [0]);
|
||||||
|
// 不等宽行:短行缺失的单元格为 undefined ≠ null,剔除该列(与原实现一致)
|
||||||
|
assert.deepEqual(allNullColumnIndexes([[null, null], [null]], [0, 1]), [0]);
|
||||||
|
// 全部候选都非 null:提前收敛返回空
|
||||||
|
assert.deepEqual(allNullColumnIndexes([[1, 2]], [0, 1]), []);
|
||||||
|
// 乱序候选:返回顺序保持 availableIndexes 原序
|
||||||
|
assert.deepEqual(allNullColumnIndexes([[null, 1, null]], [2, 0]), [2, 0]);
|
||||||
|
});
|
||||||
|
|
||||||
test("does not treat empty results as all-null columns", () => {
|
test("does not treat empty results as all-null columns", () => {
|
||||||
assert.deepEqual(allNullColumnIndexes([], [0, 1, 2]), []);
|
assert.deepEqual(allNullColumnIndexes([], [0, 1, 2]), []);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in new issue
Block a user