Skip to content

Commit

Permalink
fix: get visible cell by cursor pos
Browse files Browse the repository at this point in the history
  • Loading branch information
lumixraku committed Oct 29, 2024
1 parent 704e7eb commit 6e8ecf5
Show file tree
Hide file tree
Showing 10 changed files with 36,178 additions and 450,847 deletions.
486,604 changes: 35,942 additions & 450,662 deletions mockdata/src/sheets/demo/testdata.json

Large diffs are not rendered by default.

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);
});
});
162 changes: 102 additions & 60 deletions packages/core/src/shared/array-search.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,101 +15,143 @@
*/

/**
* Unlike ordinary bin search, It return the last position of a value in an ascending sequence list.
* 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 binarySearchArray(arr: number[], target: number) {
export function orderSearchArray(arr: number[], target: number) {
let left = 0;
let right = arr.length - 1;
let result = -1;

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

while (left <= right) {
const mid = Math.floor((left + right) / 2);
// 当找到相等的值时,需要找到最后一个相等的值的下一个位置
if (arr[left] === target) {
while (left < arr.length && arr[left] === target) {
left++;
}
return left;
}

if (arr[mid] === target) {
result = mid; // record current index
left = mid + 1; // continue to search right
} else if (arr[mid] < target) {
left = mid + 1;
} else {
right = mid - 1;
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 result;
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;
/**
* 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;

while (i < arr.length && i_ed >= 0 && i_ed >= i) {
cur = arr[i_ed];
while (low <= high) {
const mid = Math.floor((high + low) / 2);

if (i_ed === 0) {
cur_pre = 0;
if (pos < arr[mid] && (mid === 0 || pos >= arr[mid - 1])) {
return mid;
}
if (pos >= arr[mid]) {
low = mid + 1;
} else if (pos < arr[mid]) {
high = mid - 1;
} else {
cur_pre = arr[i_ed - 1];
return -1;
}
}

if (pos >= cur_pre && pos <= cur) {
cur_index = i_ed;
break;
}
return -1;
}

cur = arr[i];
/**
* 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;

if (i === 0) {
cur_pre = 0;
} else {
cur_pre = arr[i - 1];
}
while (left < right) {
const mid = Math.floor((left + right) / 2);

if (pos >= cur_pre && pos < cur) {
cur_index = i;
break;
// 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 {
right = mid;
}

i++;
i_ed--;
}

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

/**
* return last index which arr[index] > num
* ex: searchArray([1, 3, 5, 7, 9], 7) = 4
* ex: searchArray([1, 2, 3, 5, 5, 5, 5], 5) = 6
* 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 -1 ----------------> 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
*/
// if (typeof window !== undefined) {
// window.searchArray = searchArray;
// window.binarySearchArray = binarySearchArray;
// window.orderSearchArray = orderSearchArray;
// }
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) + 1;
index = binSearchFirstGreaterThanTarget(arr, target);
}

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

return index;
Expand Down
Loading

0 comments on commit 6e8ecf5

Please sign in to comment.