feat: insertItemAtArrayLike
- 정렬된 배열에 값 추가 - binary search, 뒤부터 순차 탐색 지원
This commit is contained in:
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user