Skip to content

Commit

Permalink
feat(invertBy): add invertBy to compat (#574)
Browse files Browse the repository at this point in the history
* 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
kim-sung-jee and raon0211 authored Oct 1, 2024
1 parent 83465db commit 1ff8054
Show file tree
Hide file tree
Showing 8 changed files with 271 additions and 0 deletions.
15 changes: 15 additions & 0 deletions benchmarks/performance/invertBy.bench.ts
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);
});
});
40 changes: 40 additions & 0 deletions docs/ja/reference/compat/object/invertBy.md
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'] }
```
40 changes: 40 additions & 0 deletions docs/ko/reference/compat/object/invertBy.md
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'] }
```
41 changes: 41 additions & 0 deletions docs/reference/compat/object/invertBy.md
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'] }
```
40 changes: 40 additions & 0 deletions docs/zh_hans/reference/compat/object/invertBy.md
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'] }
```
1 change: 1 addition & 0 deletions src/compat/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export { mergeWith } from './object/mergeWith.ts';
export { fromPairs } from './object/fromPairs.ts';
export { unset } from './object/unset.ts';
export { cloneDeep } from './object/cloneDeep.ts';
export { invertBy } from './object/invertBy.ts';

export { isPlainObject } from './predicate/isPlainObject.ts';
export { isArray } from './predicate/isArray.ts';
Expand Down
36 changes: 36 additions & 0 deletions src/compat/object/invertBy.spec.ts
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);
});
});
58 changes: 58 additions & 0 deletions src/compat/object/invertBy.ts
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;
}

0 comments on commit 1ff8054

Please sign in to comment.