feat: insertItemAtArrayLike

- 정렬된 배열에 값 추가
- binary search, 뒤부터 순차 탐색 지원
This commit is contained in:
2024-03-09 09:18:41 +00:00
parent 473963b58b
commit 6e7ca3f998
2 changed files with 76 additions and 0 deletions
+1
View File
@@ -6,6 +6,7 @@ export * from "./must.js"
export * from "./types.js"
export * from "./web.js"
export * from "./signal.js"
export * from "./sorted.js"
export * from "./strongType.js"
+75
View File
@@ -0,0 +1,75 @@
type IndexableRaw<T> = {
[key: number]: T;
}
type IndexableGet<T> = {
get(index: number): T | undefined;
}
type IndexableAt<T> = {
at(index: number): T;
}
interface BasicResizableArrayLike<T> {
length: number;
splice(start: number, deleteCount: number, ...items: T[]): T[] | undefined;
shift(): T | undefined;
unshift(items: T): number;
push(items: T): number;
pop(): T | undefined;
}
export type ResizableArrayLike<T> = BasicResizableArrayLike<T> & (IndexableRaw<T> | IndexableGet<T> | IndexableAt<T>);
/**
* 이미 정렬된 배열에 아이템 추가.
* Array와 Denque 지원.
*
* @param arr 정렬된 배열, splice, shift, unshift, push, pop과 at, get, []중 하나의 조회법 지원
* @param item 추가할 아이템
* @param compareFn 비교함수. 앞에 오는 경우 -1, 뒤에 오는 경우 1, 같은 경우 0을 반환해야 함.
* @param maybeTail false인 경우 binary search, true인 경우 뒤부터 순차 검색
*
* @returns
*/
export function insertItemAtArrayLike<T, Arr extends ResizableArrayLike<T>>(arr: Arr, item: T, compareFn: (a: T, b: T) => number, maybeTail = false): ResizableArrayLike<T> {
const getter: ((i: number) => T) = (() => {
if ('at' in arr) {
return (i: number) => arr.at(i)!;
}
if ('get' in arr) {
return (i: number) => arr.get(i)!;
}
return (i: number) => arr[i];
})();
if (arr.length === 0) {
arr.push(item);
return arr;
}
if (maybeTail) {
for (let i = arr.length - 1; i >= 0; i--) {
if (compareFn(getter(i), item) <= 0) {
arr.splice(i + 1, 0, item);
return arr;
}
}
//맨 앞이라고..? 대체 왜 maybeTail=true를 쓰는거지?
arr.unshift(item);
return arr;
}
//binary search and insert
let left = 0;
let right = arr.length;
while (left < right) {
const mid = (left + right) >> 1;
const cmp = compareFn(getter(mid), item);
if (cmp < 0) {
left = mid + 1;
} else {
right = mid;
}
}
arr.splice(left, 0, item);
return arr;
}