Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nasty-suns-trade.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@modern-kit/utils": minor
---

feat(utils): findLastKey 함수 추가 - @Sangminnn
42 changes: 42 additions & 0 deletions docs/docs/utils/object/findLastKey.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# findLastKey

객체에서 조건에 부합하는 마지막 key를 반환합니다.

## Code

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

## Benchmark

- `hz`: 초당 작업 수
- `mean`: 평균 응답 시간(ms)

| 이름 | hz | mean | 성능 |
| ---------------------- | ------------- | ------ | ----------- |
| modern-kit/findLastKey | 19,157,255.73 | 0.0001 | `fastest` |
| lodash/findLastKey | 7,387,616.57 | 0.0001 | `slowest` |

- **modern-kit/findLastKey**
- `2.59x` faster than lodash/findLastKey

## Interface

```ts
function findLastKey<T extends Record<PropertyKey, any>>(
obj: T,
condition: (value: T[keyof T) => boolean
): string | undefined
```

## Usage

```ts
import { findLastKey } from '@modern-kit/utils';

const obj = {
bike: { active: true },
car: { active: false },
plane: { active: true },
};
findLastKey(obj, (item) => item.active); // 'plane'
```
19 changes: 19 additions & 0 deletions packages/utils/src/object/findLastKey/findLastKey.bench.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { bench, describe } from 'vitest';
import { findLastKey } from '.';
import { findLastKey as findLastKeyLodash } from 'lodash-es';

describe('findLastKey', () => {
const obj = {
bike: { active: true },
car: { active: false },
plane: { active: true },
};

bench('modern-kit/findLastKey', () => {
findLastKey(obj, (item) => item.active);
});

bench('lodash/findLastKey', () => {
findLastKeyLodash(obj, (item) => item.active);
});
});
26 changes: 26 additions & 0 deletions packages/utils/src/object/findLastKey/findLastKey.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, expect, it } from 'vitest';
import { findLastKey } from '.';

describe('findLastKey', () => {
it('should return correct key element when a existent key-value is accessed', () => {
const obj = {
bike: { active: true },
car: { active: false },
plane: { active: true },
};

expect(findLastKey(obj, (item) => item.active)).toEqual('plane');
});

it('should return undefined when a non-existent key-value is accessed', () => {
const obj = {
bike: { active: true },
car: { active: false },
plane: { active: true },
};

expect(findLastKey(obj, (item) => (item as any).inactive)).toEqual(
undefined,
);
});
});
33 changes: 33 additions & 0 deletions packages/utils/src/object/findLastKey/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @description 객체에서 조건에 부합하는 마지막 key를 반환합니다.
*
* @template T - 키를 찾고자 하는 객체 요소의 타입
* @param {T} obj - 검색하고자 하는 객체입니다.
* @param {(value: T[keyof T]) => boolean} condition - 검색하고자 하는 조건입니다.
* @returns {string | undefined} 검색하고자 하는 조건에 부합하는 key를 반환합니다. 만약 조건에 부합하는 key가 없다면 undefined를 반환합니다.
*
* @example
* const obj = {
* bike: { active: true },
* car: { active: false },
* plane: { active: true },
* };
*
* findKey(obj, (item) => item.active); // 'plane'
*/
export function findLastKey<T extends Record<PropertyKey, any>>(
obj: T,
condition: (value: T[keyof T]) => boolean,
): string | undefined {
const keys = Object.keys(obj);

Copy link
Collaborator Author

@Sangminnn Sangminnn Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reverse 함수를 사용할 경우 불필요하게 한번 더 순회하여 성능적 이점을 가지고가기 위해 아래의 방식을 사용했습니다.

실제 reverse 함수를 사용했을때보다 실제로 성능적 이점이 있는 부분을 확인했습니다.

reverse 사용 O

스크린샷 2024-10-18 오후 11 13 06

reverse 사용 X

스크린샷 2024-10-18 오후 11 13 57

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Sangminnn 좋습니다 :) 👍

for (let i = keys.length - 1; i >= 0; i--) {
const key = keys[i];
const value = obj[key];

if (condition(value)) {
return key;
}
}
return undefined;
}
1 change: 1 addition & 0 deletions packages/utils/src/object/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './deleteFalsyProperties';
export * from './findKey';
export * from './findLastKey';
export * from './groupBy';
export * from './invert';
export * from './mapKeys';
Expand Down