-
Notifications
You must be signed in to change notification settings - Fork 294
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(invertBy): add invertBy to compat (#574)
* add invertBy to compat * add invertBy bench * add invertBy .md * Update benchmarks/performance/invertBy.bench.ts * Update docs/reference/object/invertBy.md * Update invertBy.ts * Update src/compat/object/invertBy.ts * Update invertBy.ts * update invertBy * update invertBy --------- Co-authored-by: Sojin Park <[email protected]>
- Loading branch information
1 parent
83465db
commit 1ff8054
Showing
8 changed files
with
271 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { bench, describe } from 'vitest'; | ||
import { invertBy as invertByWithCompatToolkit } from 'es-toolkit/compat'; | ||
import { invertBy as invertByWithLodash } from 'lodash'; | ||
|
||
const object = { a: 1, b: 2, c: 1, d: 4 }; | ||
|
||
describe('invertBy', () => { | ||
bench('lodash/invertBy', () => { | ||
invertByWithLodash(object); | ||
}); | ||
|
||
bench('es-toolkit/compat/invertBy', () => { | ||
invertByWithCompatToolkit(object); | ||
}); | ||
}); |
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,40 @@ | ||
# invertBy | ||
|
||
::: info | ||
この関数は互換性のために `es-toolkit/compat` からのみインポートできます。代替可能なネイティブ JavaScript API があるか、まだ十分に最適化されていないためです。 | ||
|
||
`es-toolkit/compat` からこの関数をインポートすると、[lodash と完全に同じように動作](../../../compatibility.md)します。 | ||
::: | ||
|
||
与えられたオブジェクトのキーと値を [invert](../../object/invert.md) 関数のように反転させた新しいオブジェクトを生成します。 | ||
|
||
値がどのようにキーに反転されるかを `iteratee` 関数で指定します。`iteratee` 関数が与えられない場合、値はそのままキーとして使用されます。 | ||
|
||
新しいオブジェクトの値は、`iteratee` 関数が返した値が同じキーの配列になります。 | ||
|
||
## インターフェース | ||
|
||
```typescript | ||
function invertBy<K extends PropertyKey, V>(object: Record<K, V>, iteratee?: (value: V) => string): Record<string, K[]>; | ||
``` | ||
|
||
### パラメータ | ||
|
||
- `object` (`Record<K, V>`): 反転するオブジェクト。 | ||
- `iteratee` (`(value: V) => string`): オブジェクトのキーとして反転される値を別の文字列に変換する方法を指定する関数。提供されない場合、値はそのままキーとして反転されます。 | ||
|
||
### 戻り値 | ||
|
||
(`Record<string, K[]>`): キーと値が反転したオブジェクト。キーは `iteratee` 関数で変換された値になり、値は `iteratee` 関数が返した値が同じキーの配列です。 | ||
|
||
## 例 | ||
|
||
```typescript | ||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj); | ||
// result => { '1': ['a', 'c'], '2': ['b'] } | ||
|
||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj, value => `group${value}`); | ||
// result => { 'group1': ['a', 'c'], 'group2': ['b'] } | ||
``` |
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,40 @@ | ||
# invertBy | ||
|
||
::: info | ||
이 함수는 호환성을 위한 `es-toolkit/compat` 에서만 가져올 수 있어요. 대체할 수 있는 네이티브 JavaScript API가 있거나, 아직 충분히 최적화되지 않았기 때문이에요. | ||
|
||
`es-toolkit/compat`에서 이 함수를 가져오면, [lodash와 완전히 똑같이 동작](../../../compatibility.md)해요. | ||
::: | ||
|
||
주어진 객체의 키와 값을 [invert](../../object/invert.md) 함수처럼 뒤집은 새로운 객체를 생성해요. | ||
|
||
값이 어떻게 키로 뒤집힐지를 `iteratee` 함수로 지정해요. `iteratee` 함수가 주어지지 않으면, 값이 그대로 키로 사용돼요. | ||
|
||
새로운 객체의 값은, `iteratee` 함수가 반환한 값이 같은 키들의 배열이 돼요. | ||
|
||
## 인터페이스 | ||
|
||
```typescript | ||
function invertBy<K extends PropertyKey, V>(object: Record<K, V>, iteratee?: (value: V) => string): Record<string, K[]>; | ||
``` | ||
|
||
### 파라미터 | ||
|
||
- `object` (`Record<K, V>`): 값을 뒤집을 객체. | ||
- `iteratee` (`(value: V) => string`): 객체의 키로 뒤집힐 값을 다른 문자열로 바꾸는 방법을 지정하는 함수. 제공되지 않으면, 값이 그대로 키로 뒤집혀요. | ||
|
||
### 반환 값 | ||
|
||
(`Record<string, K[]>`): 키와 값이 뒤집힌 객체. 키는 `iteratee` 함수로 변환된 값이 되고, 값은 `iteratee` 함수가 반환한 값이 같은 키들의 배열이에요. | ||
|
||
## 예시 | ||
|
||
```typescript | ||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj); | ||
// result => { '1': ['a', 'c'], '2': ['b'] } | ||
|
||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj, value => `group${value}`); | ||
// result => { 'group1': ['a', 'c'], 'group2': ['b'] } | ||
``` |
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,41 @@ | ||
# invertBy | ||
|
||
::: info | ||
This function is only available in `es-toolkit/compat` for compatibility reasons. It either has alternative native JavaScript APIs or isn’t fully optimized yet. | ||
|
||
When imported from `es-toolkit/compat`, it behaves exactly like lodash and provides the same functionalities, as detailed [here](../../../compatibility.md). | ||
::: | ||
|
||
Creates a new object that reverses the keys and values of the given object, similar to the [invert](../../object/invert.md) function. | ||
|
||
The `iteratee` function specifies how the values are reversed into keys. If no `iteratee` function is provided, the values are used as keys as-is. | ||
|
||
The values of the new object are arrays of keys that correspond to the value returned by the `iteratee` function. | ||
|
||
## Signature | ||
|
||
```typescript | ||
function invertBy<K extends PropertyKey, V>(object: Record<K, V>, iteratee?: (value: V) => string): Record<string, K[]>; | ||
``` | ||
|
||
### Parameters | ||
|
||
- `object` (`Record<K, V>`): The object to iterate over. | ||
- `iteratee` (`(value: V) => string`): A function applied to each value to generate a key. If not provided, defaults to a function that converts the value to a string. | ||
|
||
### Returns | ||
|
||
- `(Record<string, K[]>)`: An object where each key is the result of the iteratee, and the corresponding value is an array of property names from the input object that produced that value. | ||
|
||
### Examples | ||
|
||
```typescript | ||
import { invertBy } from 'es-toolkit/compat'; | ||
|
||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj); | ||
console.log(result); // => { '1': ['a', 'c'], '2': ['b'] } | ||
|
||
const customResult = invertBy(obj, value => `group${value}`); | ||
console.log(customResult); // => { 'group1': ['a', 'c'], 'group2': ['b'] } | ||
``` |
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,40 @@ | ||
# invertBy | ||
|
||
::: info | ||
出于兼容性原因,此函数仅在 `es-toolkit/compat` 中提供。它可能具有替代的原生 JavaScript API,或者尚未完全优化。 | ||
|
||
从 `es-toolkit/compat` 导入时,它的行为与 lodash 完全一致,并提供相同的功能,详情请见 [这里](../../../compatibility.md)。 | ||
::: | ||
|
||
给定对象的键和值会像 [invert](../../object/invert.md) 函数一样被反转,生成一个新的对象。 | ||
|
||
如何将值反转为键由 `iteratee` 函数指定。如果未提供 `iteratee` 函数,则值将直接用作键。 | ||
|
||
新对象的值是 `iteratee` 函数返回的值对应的键的数组。 | ||
|
||
## 签名 | ||
|
||
```typescript | ||
function invertBy<K extends PropertyKey, V>(object: Record<K, V>, iteratee?: (value: V) => string): Record<string, K[]>; | ||
``` | ||
|
||
### 参数 | ||
|
||
- `object` (`Record<K, V>`): 需要反转的对象。 | ||
- `iteratee` (`(value: V) => string`): 指定如何将对象的值转换为其他字符串的函数。如果未提供,则值将直接用作键。 | ||
|
||
### 返回值 | ||
|
||
(`Record<string, K[]>`): 反转后的对象。键是通过 `iteratee` 函数转换的值,值是与这些值相同的键的数组。 | ||
|
||
## 示例 | ||
|
||
```typescript | ||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj); | ||
// result => { '1': ['a', 'c'], '2': ['b'] } | ||
|
||
const obj = { a: 1, b: 2, c: 1 }; | ||
const result = invertBy(obj, value => `group${value}`); | ||
// result => { 'group1': ['a', 'c'], 'group2': ['b'] } | ||
``` |
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,36 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { invertBy } from './invertBy.ts'; | ||
|
||
/** | ||
* @see https://github.com/lodash/lodash/blob/6a2cc1dfcf7634fea70d1bc5bd22db453df67b42/test/invertBy.spec.js | ||
*/ | ||
|
||
describe('invertBy', () => { | ||
const object = { a: 1, b: 2, c: 1 }; | ||
|
||
it('should transform keys by `iteratee`', () => { | ||
const expected = { group1: ['a', 'c'], group2: ['b'] }; | ||
|
||
const actual = invertBy(object, value => `group${value}`); | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
|
||
it('should use `identity` when `iteratee` is nullish', () => { | ||
const values = [undefined, null]; | ||
const expected = values.map(() => ({ '1': ['a', 'c'], '2': ['b'] })); | ||
|
||
const actual = values.map((value, index) => (index ? invertBy(object, value as any) : invertBy(object))); | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
|
||
it('should only add multiple values to own, not inherited, properties', () => { | ||
const objectWithInheritedProps = { a: 'hasOwnProperty', b: 'constructor' }; | ||
const expected = { hasOwnProperty: ['a'], constructor: ['b'] }; | ||
|
||
const actual = invertBy(objectWithInheritedProps); | ||
|
||
expect(actual).toEqual(expected); | ||
}); | ||
}); |
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,58 @@ | ||
import { isNil } from '../../predicate/isNil.ts'; | ||
import { identity } from '../_internal/identity.ts'; | ||
|
||
/** | ||
* Creates a new object that reverses the keys and values of the given object, similar to the invert. | ||
* | ||
* The `iteratee` function specifies how the values are reversed into keys. If no `iteratee` function is provided, the values are used as keys as-is. | ||
* | ||
* The values of the new object are arrays of keys that correspond to the value returned by the `iteratee` function. | ||
* | ||
* @param {Record<K, V>} object - The object to iterate over. | ||
* @param {(value: V) => string} [iteratee] - Optional. A function that generates a key based on each value in the object. | ||
* If not provided, the function defaults to using the value as a string. | ||
* | ||
* @returns {Record<string, K[]>} An object where the keys are generated by the iteratee, and the values | ||
* are arrays of property names (keys) from the input object that correspond to those keys. | ||
* | ||
* @example | ||
* const obj = { a: 1, b: 2, c: 1 }; | ||
* const result = invertBy(obj); | ||
* // result => { '1': ['a', 'c'], '2': ['b'] } | ||
* | ||
* @example | ||
* const obj = { a: 1, b: 2, c: 1 }; | ||
* const result = invertBy(obj, value => `group${value}`); | ||
* // result => { 'group1': ['a', 'c'], 'group2': ['b'] } | ||
*/ | ||
export function invertBy<K extends PropertyKey, V>( | ||
object: Record<K, V>, | ||
iteratee?: (value: V) => string | ||
): Record<string, K[]> { | ||
const result = {} as Record<string, K[]>; | ||
|
||
if (isNil(object)) { | ||
return result; | ||
} | ||
|
||
if (iteratee == null) { | ||
iteratee = identity as (value: V) => string; | ||
} | ||
|
||
const keys = Object.keys(object); | ||
|
||
for (let i = 0; i < keys.length; i++) { | ||
const key = keys[i] as K; | ||
|
||
const value = object[key]; | ||
const valueStr = iteratee(value); | ||
|
||
if (Array.isArray(result[valueStr])) { | ||
result[valueStr].push(key); | ||
} else { | ||
result[valueStr] = [key]; | ||
} | ||
} | ||
|
||
return result; | ||
} |