Skip to content

Commit

Permalink
fix: get visible cell by cursor pos by fixing searchArray
Browse files Browse the repository at this point in the history
  • Loading branch information
lumixraku committed Oct 30, 2024
1 parent 4e31b24 commit 3987399
Show file tree
Hide file tree
Showing 10 changed files with 197 additions and 182 deletions.
1 change: 0 additions & 1 deletion mockdata/src/sheets/demo/default-workbook-data-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13985,7 +13985,6 @@ export const DEFAULT_WORKBOOK_DATA_DEMO: IWorkbookData = {
rowCount: 1000,
columnCount: 20,
zoomRatio: 1,
defaultStyle: 'defaultSheetStyle',
cellData: {
0: {
0: {
Expand Down
46 changes: 46 additions & 0 deletions packages/core/src/shared/__tests__/search-array.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { describe, expect, it } from 'vitest';
import { binSearchFirstGreaterThanTarget, orderSearchArray, searchArray } from '../array-search';

describe('test searchArray function', () => {
const array = [0, 1, 2, 3, 4, 4, 4, 5, 5, 5];

it('searchArray test', () => {
expect(searchArray(array, -1)).toBe(array.indexOf(0));
expect(searchArray(array, 0)).toBe(array.indexOf(1));
expect(searchArray(array, 4)).toBe(array.indexOf(5));
expect(searchArray(array, 5)).toBe(array.length - 1);
expect(searchArray(array, 8)).toBe(array.length - 1);
});

it('orderSearchArray test', () => {
expect(orderSearchArray(array, -1)).toBe(array.indexOf(0));
expect(orderSearchArray(array, 0)).toBe(array.indexOf(1));
expect(orderSearchArray(array, 4)).toBe(array.indexOf(5));
expect(orderSearchArray(array, 5)).toBe(array.length - 1);
expect(orderSearchArray(array, 8)).toBe(array.length - 1);
});

it('binSearchFirstGreaterThanTarget test', () => {
expect(searchArray(array, -1)).toBe(array.indexOf(0));
expect(binSearchFirstGreaterThanTarget(array, 0)).toBe(array.indexOf(1));
expect(binSearchFirstGreaterThanTarget(array, 4)).toBe(array.indexOf(5));
expect(binSearchFirstGreaterThanTarget(array, 5)).toBe(array.length - 1);
expect(binSearchFirstGreaterThanTarget(array, 8)).toBe(array.length - 1);
});
});
146 changes: 99 additions & 47 deletions packages/core/src/shared/array-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,61 @@
* limitations under the License.
*/

/**
* Return the index of the first value in an ascending array that is greater than the target value. If there is no value greater than the target, return -1.
*
* Alternatively, you can consider inserting a number to ensure the array remains sorted, and return the position for insertion. If the target is the same as the maximum value, return -1. (or arr.length -1)
* @param arr
* @param target
*/
export function orderSearchArray(arr: number[], target: number) {
let left = 0;
let right = arr.length - 1;

if (target < arr[0]) return 0;
if (target >= arr[arr.length - 1]) return arr.length - 1;

while (left <= right) {
// When an equal value is found, it is necessary to find the position immediately following the last occurrence of that equal value.
if (arr[left] === target) {
while (left < arr.length && arr[left] === target) {
left++;
}
return left;
}

if (target > arr[left] && target < arr[left + 1]) {
return left + 1;
}

if (arr[right] === target) {
while (right < arr.length && arr[right] === target) {
right++;
}
return right;
}

if (target > arr[right - 1] && target < arr[right]) {
return right;
}

left++;
right--;
}

return -1;
}

/**
* Return the index of the first value in an ascending array that is greater than the target value. If there is no value greater than the target, return -1.
*
*
* binarySearchArray([0,1,2,3,4, 4, 4,5, 5, 5], 1) return 2
* binarySearchArray([0,1,2,3,4, 4, 4, 5, 5, 5], 5) return -1, because max value 5 is not greater than target 5
* binarySearchArray([0,1,2,3,4, 4, 4, 5, 5, 5], 8) return -1, because max value 5 is not greater than target 8
* @param arr
* @param pos
*/
export function binarySearchArray(arr: number[], pos: number) {
let low: number = 0;
let high = arr.length - 1;
Expand All @@ -36,70 +91,67 @@ export function binarySearchArray(arr: number[], pos: number) {
return -1;
}

export function orderSearchArray(arr: number[], pos: number) {
let i = 0;
let cur = 0;
let cur_pre = 0;
let cur_index = -1;
let i_ed = arr.length - 1;

while (i < arr.length && i_ed >= 0 && i_ed >= i) {
cur = arr[i_ed];

if (i_ed === 0) {
cur_pre = 0;
} else {
cur_pre = arr[i_ed - 1];
}

if (pos >= cur_pre && pos <= cur) {
cur_index = i_ed;
break;
}
/**
* Return the index of the first value in an ascending array that is greater than the target value. If there is no value greater than the target, return -1.
*
* Alternatively, you can consider inserting a number to ensure the array remains sorted, and return the position for insertion. If the target is the same as the maximum value, return -1.
*
* binarySearchArray([0,1,2,3,4, 4, 4,5, 5, 5], 1) return 2
* binarySearchArray([0,1,2,3,4, 4, 4, 5, 5, 5], 5) return -1, because max value 5 is not greater than target 5
* binarySearchArray([0,1,2,3,4, 4, 4, 5, 5, 5], 8) return -1, because max value 5 is not greater than target 8
* @param arr
* @param target
*/
export function binSearchFirstGreaterThanTarget(arr: number[], target: number) {
let left = 0;
let right = arr.length;

cur = arr[i];
while (left < right) {
const mid = Math.floor((left + right) / 2);

if (i === 0) {
cur_pre = 0;
// If the middle value is less than or equal to the target value, continue searching in the right half.
if (arr[mid] <= target) {
left = mid + 1;
} else {
cur_pre = arr[i - 1];
}

if (pos >= cur_pre && pos < cur) {
cur_index = i;
break;
right = mid;
}

i++;
i_ed--;
}

return cur_index;
// Returns the index of the first element greater than the target value;
// returns last index if no value in array is greater than target.
return left < arr.length ? left : arr.length - 1;
}

/**
* return the first index which arr[index] > num
* ex: searchArray([1, 3, 5, 7, 9], 7) = 4
* Return the index of the first value in an ascending array that is greater than the target value.
* If target is greater than biggest value, return arr.length -1(last biggest value index).
* If target is equal to biggest value, return arr.length -1(last biggest value index);
*
* searchArray([0, 1, 2, 3, 4, 4, 4, 5, 5, 5], 1) return 2
* searchArray([0, 1, 2, 3, 4, 4, 4, 5, 5, 5], 1) return 7 (first 5 index)
* searchArray([0, 1, 2, 3, 4, 4, 4, 5, 5, 5], 5) return 9
* searchArray([0, 1, 2, 3, 4, 4, 4, 5, 5, 5], 8) return 9
*
* @param arr
* @param num
* @param target
* @returns {number} index
*/
export function searchArray(arr: number[], num: number) {
export function searchArray(arr: number[], target: number, firstMatch = false) {
let index: number = arr.length - 1;
if (num < 0) {
return -1;
}
if (num < arr[0]) {
if (target < 0 || target < arr[0]) {
return 0;
}
if (num > arr[arr.length - 1]) {
return Number.POSITIVE_INFINITY;
}

if (arr.length < 40 || num <= arr[20] || num >= arr[index - 20]) {
index = orderSearchArray(arr, num);
// Excluding the special conditions mentioned above, the next return values can only be between 1 and length - 1.
if (arr.length < 40 || target <= arr[20] || target >= arr[index - 20]) {
index = orderSearchArray(arr, target);
} else {
index = binarySearchArray(arr, num);
index = binSearchFirstGreaterThanTarget(arr, target);
}

if (firstMatch) {
const val = arr[index];
return arr.indexOf(val);
}

return index;
Expand Down
Loading

0 comments on commit 3987399

Please sign in to comment.