Skip to content

Commit

Permalink
feat(utils): countOccurrencesInArray 유틸 함수 추가 (#159)
Browse files Browse the repository at this point in the history
* feat(utils): countOccurrencesInArray 유틸 함수 추가

* docs: 문서 수정
  • Loading branch information
ssi02014 authored May 23, 2024
1 parent 589dd5b commit 7842e3e
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 7 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-jeans-film.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/utils': minor
---

feat(utils): countOccurrencesInArray 유틸 함수 추가 - @ssi02014
34 changes: 34 additions & 0 deletions docs/docs/utils/array/countOccurrencesInArray.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# countOccurrencesInArray

입력한 배열에서 배열의 각 요소들이 등장한 횟수를 카운팅 해주는 유틸 함수입니다.

💡 단, `Object`, `Array`, `Set`, `Map`과 같은 객체 타입은 카운팅에서 제외되며, `null`, `NaN`, `undefined`는 카운팅에 포함됩니다.

<br />

## Code
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/array/countOccurrencesInArray/index.ts)

## Interface
```ts title="typescript"
const countOccurrencesInArray: <T extends readonly any[]>(
arr: T
) => Record<Exclude<T[number], object>, number>;
```

## Usage
```ts title="typescript"
import { countOccurrencesInArray } from '@modern-kit/utils';

const arr = [
'foo',
'foo',
'foo',
1,
1,
[1], // exclude
{ a: 1 }, // exclude
];

const countingObj = countOccurrencesInArray(arr); // { foo: 3, 1: 2 }
```
3 changes: 1 addition & 2 deletions docs/docs/utils/validator/isArray.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,14 @@

## Interface
```ts title="typescript"
const isArray: <T>(value: unknown) => value is T[]
const isArray: <T extends readonly any[]>(value: unknown) => value is T
```
## Usage
```ts title="typescript"
import { isArray } from '@modern-kit/utils';

isArray([]); // true

isArray(() => {}); // false
isArray('123'); // false
isArray(123); // false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { countOccurrencesInArray } from '.';

describe('countOccurrencesInArray', () => {
it('should count occurrences of each value correctly', () => {
const testArray1 = [
'foo',
'foo',
'foo',
1,
1,
false,
false,
null,
null,
undefined,
NaN,
[1], // exclude
{ a: 1 }, // exclude
new Set(), // exclude
new Map(), // exclude
];

expect(countOccurrencesInArray(testArray1)).toEqual({
foo: 3,
1: 2,
false: 2,
null: 2,
undefined: 1,
NaN: 1,
});

const testArray2: string[] = [];

expect(countOccurrencesInArray(testArray2)).toEqual({});
});

it('should correctly type the result object based on input array types', () => {
const readonlyTestArray = [
'foo',
'foo',
'bar',
1,
2,
[1], // exclude
{ a: 1 }, // exclude
] as const;

expectTypeOf(countOccurrencesInArray(readonlyTestArray)).toEqualTypeOf<
Record<'foo' | 1 | 2 | 'bar', number>
>();

const defaultTestArray = [
'foo',
'foo',
'bar',
1,
2,
[1], // exclude
{ a: 1 }, // exclude
];

expectTypeOf(countOccurrencesInArray(defaultTestArray)).toEqualTypeOf<
Record<string | number, number>
>();
});
});
13 changes: 13 additions & 0 deletions packages/utils/src/array/countOccurrencesInArray/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const countOccurrencesInArray = <T extends readonly any[]>(
arr: T
): Record<Exclude<T[number], object>, number> => {
return arr.reduce((acc, cur) => {
if (typeof cur === 'object' && cur != null) {
return acc;
}

acc[cur] = (acc[cur] || 0) + 1;

return acc;
}, {});
};
1 change: 1 addition & 0 deletions packages/utils/src/array/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './countOccurrencesInArray';
1 change: 1 addition & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './array';
export * from './clipboard';
export * from './common';
export * from './device';
Expand Down
4 changes: 3 additions & 1 deletion packages/utils/src/validator/isArray/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export const isArray = <T>(value: unknown): value is Array<T> => {
export const isArray = <T extends readonly any[]>(
value: unknown
): value is T => {
return Array.isArray(value);
};
14 changes: 10 additions & 4 deletions packages/utils/src/validator/isArray/isArray.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,18 @@ describe('isArray', () => {
});

it('should narrow the type through if statements', () => {
const testValue = ['foo'] as string | string[];
const defaultTestArray = ['foo'] as string | string[];

if (isArray<string>(testValue)) {
expectTypeOf(testValue).toEqualTypeOf<string[]>();
if (isArray(defaultTestArray)) {
expectTypeOf(defaultTestArray).toEqualTypeOf<string[]>();
} else {
expectTypeOf(testValue).toEqualTypeOf<string>();
expectTypeOf(defaultTestArray).toEqualTypeOf<string>();
}

const readonlyTestArray = ['foo'] as const;

if (isArray(readonlyTestArray)) {
expectTypeOf(readonlyTestArray).toEqualTypeOf<readonly ['foo']>();
}
});
});

0 comments on commit 7842e3e

Please sign in to comment.