feat: insertItemAtArrayLike
- 정렬된 배열에 값 추가 - binary search, 뒤부터 순차 탐색 지원
This commit is contained in:
@@ -6,6 +6,7 @@ export * from "./must.js"
|
|||||||
export * from "./types.js"
|
export * from "./types.js"
|
||||||
export * from "./web.js"
|
export * from "./web.js"
|
||||||
export * from "./signal.js"
|
export * from "./signal.js"
|
||||||
|
export * from "./sorted.js"
|
||||||
|
|
||||||
export * from "./strongType.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