Skip to content

Commit

Permalink
add : insert 함수 생성
Browse files Browse the repository at this point in the history
  • Loading branch information
김태헌 authored and 김태헌 committed Oct 1, 2024
1 parent d177c15 commit d3b7ed4
Show file tree
Hide file tree
Showing 4 changed files with 266 additions and 0 deletions.
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
- [find](#find)
- [flat](#flat)
- [flatMap](#flatmap)
- [insert](#insert)
- [interval](#interval)
- [join](#join)
- [length](#length)
Expand Down Expand Up @@ -237,6 +238,16 @@ const res2 = await pipe(

- **예시(Example)** : https://github.com/gangnamssal/mori-ts/wiki/flatMap

### insert

- 주어진 `인덱스`에 값을 `삽입`한 iterable을 반환합니다.

- 동기 및 비동기 iterable 모두 지원하며, iterable의 끝에 도달해도 값을 삽입할 수 있습니다.

- 삽입되는 값은 Promise로 감싸져 비동기적으로도 처리 가능합니다.

- **예시(Example)** : https://github.com/gangnamssal/mori-ts/wiki/insert

### interval

- 주어진 지연 시간 동안 `각 요소를 대기`하면서 제공된 iterable을 반환하는 함수입니다.
Expand Down
1 change: 1 addition & 0 deletions src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export { default as filter } from './filter/filter';
export { default as find } from './find/find';
export { default as flat } from './flat/flat';
export { default as flatMap } from './flat-map/flat-map';
export { default as insert } from './insert/insert';
export { default as interval } from './interval/interval';
export { default as join } from './join/join';
export { default as length } from './length/length';
Expand Down
159 changes: 159 additions & 0 deletions src/core/insert/insert.ts
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;
95 changes: 95 additions & 0 deletions src/test/insert.spec.ts
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');
});
});

0 comments on commit d3b7ed4

Please sign in to comment.