-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
김태헌
authored and
김태헌
committed
Oct 1, 2024
1 parent
d177c15
commit d3b7ed4
Showing
4 changed files
with
266 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import { isAsyncIterable, isIterable } from './../../utils'; | ||
import { IterableInfer, ReturnIterableIteratorType } from '../../types'; | ||
|
||
function syncInsert<A, B>(index: number, insertValue: B, iter: Iterable<A>): IterableIterator<A | B> { | ||
const iterator = iter[Symbol.iterator](); | ||
let currentIndex = 0; | ||
let insertDone = false; | ||
|
||
return { | ||
[Symbol.iterator]() { | ||
return this; | ||
}, | ||
|
||
next() { | ||
if (!insertDone && currentIndex === index) { | ||
insertDone = true; | ||
return { done: false, value: insertValue }; | ||
} | ||
|
||
const { value, done } = iterator.next(); | ||
|
||
if (done) { | ||
if (!insertDone) { | ||
insertDone = true; | ||
return { done: false, value: insertValue }; | ||
} | ||
|
||
return { done: true, value: undefined }; | ||
} | ||
|
||
currentIndex++; | ||
return { done: false, value }; | ||
}, | ||
}; | ||
} | ||
|
||
function asyncInsert<A, B>( | ||
index: number, | ||
insertValue: B, | ||
iter: AsyncIterable<A>, | ||
): AsyncIterableIterator<A | B> { | ||
const iterator = iter[Symbol.asyncIterator](); | ||
let currentIndex = 0; | ||
let insertDone = false; | ||
|
||
return { | ||
[Symbol.asyncIterator]() { | ||
return this; | ||
}, | ||
|
||
async next() { | ||
if (!insertDone && currentIndex === index) { | ||
insertDone = true; | ||
return { done: false, value: await insertValue }; | ||
} | ||
|
||
const { value, done } = await iterator.next(); | ||
|
||
if (done) { | ||
if (!insertDone) { | ||
insertDone = true; | ||
return { done: false, value: await insertValue }; | ||
} | ||
|
||
return { done: true, value: undefined }; | ||
} | ||
|
||
currentIndex++; | ||
return { done: false, value }; | ||
}, | ||
}; | ||
} | ||
|
||
type ReturnInsertIterableIteratorType< | ||
A extends Iterable<unknown> | AsyncIterable<unknown>, | ||
B, | ||
> = ReturnIterableIteratorType<A, IterableInfer<A> | B>; | ||
|
||
/** | ||
* @description | ||
* - 주어진 인덱스에 값을 삽입한 iterable을 반환합니다. | ||
* - 동기 및 비동기 iterable 모두 지원하며, iterable의 끝에 도달해도 값을 삽입할 수 있습니다. | ||
* - 삽입되는 값은 Promise로 감싸져 비동기적으로도 처리 가능합니다. | ||
* | ||
* @example | ||
* - 배열에서 사용 | ||
* ``` | ||
* const arr = [1, 2]; | ||
* | ||
* const result = insert(1, 3, arr); | ||
* console.log([...result]); // 출력: [1, 3, 2] | ||
* | ||
* const result2 = insert(1, 3, arr); | ||
* console.log(toArray(result2)); // 출력: [1, 3, 2] | ||
* ``` | ||
* | ||
* @example | ||
* - 끝에 값을 삽입 | ||
* ``` | ||
* const arr = [1, 2]; | ||
* | ||
* const result = insert(5, 3, arr); | ||
* console.log([...result]); // 출력: [1, 2, 3] | ||
* ``` | ||
* | ||
* @example | ||
* - pipe와 함께 사용 | ||
* ``` | ||
* const iter = [1, 2, 3]; | ||
* | ||
* const res = pipe( | ||
* iter, | ||
* insert(2, 4), | ||
* toArray, | ||
* ); | ||
* console.log(res); // 출력: [1, 2, 4, 3] | ||
* | ||
* const result = await pipe( | ||
* iter, | ||
* toAsync, | ||
* insert(1, 4), | ||
* toArray, | ||
* ); | ||
* console.log(result); // 출력: [1, 4, 2, 3] | ||
* ``` | ||
* | ||
* @url https://github.com/gangnamssal/mori-ts/wiki/insert | ||
*/ | ||
|
||
function insert<A extends Iterable<unknown> | AsyncIterable<unknown>, B>( | ||
index: number, | ||
insertValue: B, | ||
iter: A, | ||
): ReturnInsertIterableIteratorType<A, B>; | ||
|
||
function insert<A extends Iterable<unknown> | AsyncIterable<unknown>, B>( | ||
index: number, | ||
insertValue: B, | ||
): (iter: A) => ReturnInsertIterableIteratorType<A, B>; | ||
|
||
function insert<A extends Iterable<unknown> | AsyncIterable<unknown>, B>( | ||
index: number, | ||
insertValue: B, | ||
iter?: A, | ||
): ReturnInsertIterableIteratorType<A, B> | ((iter: A) => ReturnInsertIterableIteratorType<A, B>) { | ||
if (iter === undefined) | ||
return (iter: A): ReturnInsertIterableIteratorType<A, B> => | ||
insert(index, insertValue, iter) as ReturnInsertIterableIteratorType<A, B>; | ||
|
||
if (isIterable<A>(iter)) | ||
return syncInsert(index, insertValue, iter) as ReturnInsertIterableIteratorType<A, B>; | ||
|
||
if (isAsyncIterable<A>(iter)) | ||
return asyncInsert(index, insertValue, iter) as ReturnInsertIterableIteratorType<A, B>; | ||
|
||
throw new Error('argument is not valid'); | ||
} | ||
|
||
export default insert; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { filter, insert, join, map, pipe, range, toArray, toAsync } from '../core'; | ||
|
||
describe('insert', () => { | ||
it('inserts a value at the specified index', () => { | ||
const result = insert(1, 3, [1, 2]); | ||
expect([...result]).toEqual([1, 3, 2]); | ||
}); | ||
|
||
it('inserts a value at the beginning of the iterable', () => { | ||
const result = insert(0, 3, [1, 2]); | ||
expect([...result]).toEqual([3, 1, 2]); | ||
}); | ||
|
||
it('inserts a value at the end of the iterable', () => { | ||
const result = insert(2, 3, [1, 2]); | ||
expect([...result]).toEqual([1, 2, 3]); | ||
}); | ||
|
||
it('inserts a value at the end of the iterable 2', () => { | ||
const result = insert(5, 3, [1, 2]); | ||
expect([...result]).toEqual([1, 2, 3]); | ||
}); | ||
|
||
it('inserts a value at the specified index (async)', async () => { | ||
const result = await pipe([1, 2], toAsync, insert(1, 3), toArray); | ||
|
||
expect(result).toEqual([1, 3, 2]); | ||
}); | ||
|
||
it('inserts a value at the beginning of the iterable (async)', async () => { | ||
const result = await pipe([1, 2], toAsync, insert(0, 3), toArray); | ||
|
||
expect(result).toEqual([3, 1, 2]); | ||
}); | ||
|
||
it('inserts a value at the end of the iterable (async)', async () => { | ||
const result = await pipe([1, 2], toAsync, insert(2, 3), toArray); | ||
|
||
expect(result).toEqual([1, 2, 3]); | ||
}); | ||
|
||
it('inserts a value at the end of the iterable 2 (async)', async () => { | ||
const result = await pipe([1, 2], toAsync, insert(5, 3), toArray); | ||
|
||
expect(result).toEqual([1, 2, 3]); | ||
}); | ||
|
||
it('inserts with promise value', async () => { | ||
const result = await pipe([1, 2], toAsync, insert(1, Promise.resolve(3)), toArray); | ||
|
||
expect(result).toEqual([1, 3, 2]); | ||
}); | ||
|
||
it('inserts with promise value 2', () => { | ||
const result = pipe([1, 2], insert(1, Promise.resolve(3)), toArray); | ||
|
||
expect(result).toEqual([1, Promise.resolve(3), 2]); | ||
}); | ||
|
||
it('inserts with pipe', () => { | ||
const res = pipe( | ||
range(1, 10), | ||
insert(5, 100), | ||
map(a => a + 1), | ||
filter(a => a % 2 !== 0), | ||
toArray, | ||
); | ||
|
||
expect(res).toEqual([3, 5, 101, 7, 9]); | ||
}); | ||
|
||
it('inserts with pipe 2', async () => { | ||
const res = await pipe( | ||
[Promise.resolve(1), Promise.resolve(2), Promise.resolve(3), Promise.resolve(4), Promise.resolve(5)], | ||
toAsync, | ||
insert(3, 100), | ||
map(a => a + 1), | ||
toArray, | ||
); | ||
|
||
expect(res).toEqual([2, 3, 4, 101, 5, 6]); | ||
}); | ||
|
||
it('inserts with string', () => { | ||
const res = pipe('hello', insert(3, 'l'), join('')); | ||
|
||
expect(res).toEqual('helllo'); | ||
}); | ||
|
||
it('inserts with string 2', () => { | ||
const res = pipe('', insert(3, 'l'), join('')); | ||
|
||
expect(res).toEqual('l'); | ||
}); | ||
}); |