mirror of
https://github.com/toss/es-toolkit.git
synced 2024-11-24 11:45:26 +03:00
feat(rearg): Implement rearg (#426)
* feat(rearg): implement rearg * make lint happy * fix * make lint happy --------- Co-authored-by: Sojin Park <raon0211@toss.im>
This commit is contained in:
parent
887aa4d4f4
commit
ff595628cd
18
benchmarks/performance/rearg.bench.ts
Normal file
18
benchmarks/performance/rearg.bench.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { rearg as reargToolkit } from 'es-toolkit/compat';
|
||||
import { rearg as reargLodash } from 'lodash';
|
||||
|
||||
describe('rearg', () => {
|
||||
function fn() {
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
return Array.from(arguments);
|
||||
}
|
||||
|
||||
bench('es-toolkit/rearg', () => {
|
||||
reargToolkit(fn, [2, 0, 1]);
|
||||
});
|
||||
|
||||
bench('lodash/rearg', () => {
|
||||
reargLodash(fn, [2, 0, 1]);
|
||||
});
|
||||
});
|
37
docs/reference/function/rearg.md
Normal file
37
docs/reference/function/rearg.md
Normal file
@ -0,0 +1,37 @@
|
||||
# rearg
|
||||
|
||||
Creates a function that invokes `func` with arguments arranged according to the specified `indexes` where the argument value at the first index is provided as the first argument, the argument value at the second index is provided as the second argument, and so on.
|
||||
|
||||
## Signature
|
||||
|
||||
```typescript
|
||||
function rearg<F extends (...args: any[]) => any>(
|
||||
func: F,
|
||||
...indexes: Array<number | number[]>
|
||||
): (...args: any[]) => ReturnType<F>;
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- `func` (`F`): The function to rearrange arguments for.
|
||||
- `indexes` (`Array<number | number[]>`): The arranged argument indexes.
|
||||
|
||||
### Returns
|
||||
|
||||
(`(...args: any[]) => ReturnType<F>`): Returns the new function.
|
||||
|
||||
## Examples
|
||||
|
||||
```typescript
|
||||
import { rearg } from 'es-toolkit/function';
|
||||
|
||||
const rearged = rearg(
|
||||
function (a, b, c) {
|
||||
return [a, b, c];
|
||||
},
|
||||
[2, 0, 1]
|
||||
);
|
||||
|
||||
rearged('b', 'c', 'a');
|
||||
// => ['a', 'b', 'c']
|
||||
```
|
37
docs/zh_hans/reference/function/rearg.md
Normal file
37
docs/zh_hans/reference/function/rearg.md
Normal file
@ -0,0 +1,37 @@
|
||||
# rearg
|
||||
|
||||
创建一个函数,该函数根据指定的 `indexes` 重新排列参数来调用 `func`,其中第一个索引位置的参数值作为第一个参数,第二个索引位置的参数值作为第二个参数,依此类推。
|
||||
|
||||
## 签名
|
||||
|
||||
```typescript
|
||||
function rearg<F extends (...args: any[]) => any>(
|
||||
func: F,
|
||||
...indexes: Array<number | number[]>
|
||||
): (...args: any[]) => ReturnType<F>;
|
||||
```
|
||||
|
||||
### 参数
|
||||
|
||||
- `func` (`F`): 用于重新排列参数的函数。
|
||||
- `indexes` (`Array<number | number[]>`): 排列后的参数索引。
|
||||
|
||||
### 返回值
|
||||
|
||||
(`(...args: any[]) => ReturnType<F>`): 返回新的函数。
|
||||
|
||||
## 示例
|
||||
|
||||
```typescript
|
||||
import { rearg } from 'es-toolkit/function';
|
||||
|
||||
const rearged = rearg(
|
||||
function (a, b, c) {
|
||||
return [a, b, c];
|
||||
},
|
||||
[2, 0, 1]
|
||||
);
|
||||
|
||||
rearged('b', 'c', 'a');
|
||||
// => ['a', 'b', 'c']
|
||||
```
|
@ -11,4 +11,5 @@ export { unary } from './unary.ts';
|
||||
export { partial } from './partial.ts';
|
||||
export { partialRight } from './partialRight.ts';
|
||||
export { rest } from './rest.ts';
|
||||
export { rearg } from './rearg.ts';
|
||||
export { spread } from './spread.ts';
|
||||
|
62
src/function/rearg.spec.ts
Normal file
62
src/function/rearg.spec.ts
Normal file
@ -0,0 +1,62 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { rearg } from './rearg';
|
||||
|
||||
describe('rearg', () => {
|
||||
function fn() {
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
return Array.from(arguments);
|
||||
}
|
||||
|
||||
it('should reorder arguments provided to `func`', () => {
|
||||
const rearged = rearg(fn, [2, 0, 1]);
|
||||
expect(rearged('b', 'c', 'a')).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should work with repeated indexes', () => {
|
||||
const rearged = rearg(fn, [1, 1, 1]);
|
||||
expect(rearged('c', 'a', 'b')).toEqual(['a', 'a', 'a']);
|
||||
});
|
||||
|
||||
it('should use `undefined` for nonexistent indexes', () => {
|
||||
const rearged = rearg(fn, [1, 4]);
|
||||
expect(rearged('b', 'a', 'c')).toEqual(['a', undefined, 'c']);
|
||||
});
|
||||
|
||||
it('should use `undefined` for non-index values', () => {
|
||||
const values = [{}, null, undefined, false, NaN, '', -1, 1.1];
|
||||
for (const value of values) {
|
||||
// @ts-expect-error - invalid args
|
||||
const rearged = rearg(fn, value);
|
||||
expect(rearged('a', 'b', 'c')).toEqual([undefined, 'b', 'c']);
|
||||
}
|
||||
});
|
||||
|
||||
it('should not rearrange arguments when no indexes are given', () => {
|
||||
let rearged = rearg(fn);
|
||||
expect(rearged('a', 'b', 'c')).toEqual(['a', 'b', 'c']);
|
||||
|
||||
rearged = rearg(fn, [], []);
|
||||
expect(rearged('a', 'b', 'c')).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should accept multiple index arguments', () => {
|
||||
const rearged = rearg(fn, 2, 0, 1);
|
||||
expect(rearged('b', 'c', 'a')).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should accept multiple arrays of indexes', () => {
|
||||
const rearged = rearg(fn, [2], [0, 1]);
|
||||
expect(rearged('b', 'c', 'a')).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should work with fewer indexes than arguments', () => {
|
||||
const rearged = rearg(fn, [1, 0]);
|
||||
expect(rearged('b', 'a', 'c')).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
|
||||
it('should work on functions that have been rearged', () => {
|
||||
const rearged1 = rearg(fn, 2, 1, 0),
|
||||
rearged2 = rearg(rearged1, 1, 0, 2);
|
||||
expect(rearged2('b', 'c', 'a')).toEqual(['a', 'b', 'c']);
|
||||
});
|
||||
});
|
28
src/function/rearg.ts
Normal file
28
src/function/rearg.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { flatten } from '../array/flatten.ts';
|
||||
|
||||
/**
|
||||
* Creates a function that invokes `func` with arguments arranged according to the specified `indexes`
|
||||
* where the argument value at the first index is provided as the first argument,
|
||||
* the argument value at the second index is provided as the second argument, and so on.
|
||||
*
|
||||
* @template F The type of the function to re-arrange.
|
||||
* @param {F} func The function to rearrange arguments for.
|
||||
* @param {Array<number | number[]>} indexes The arranged argument indexes.
|
||||
* @returns {(...args: any[]) => ReturnType<F>} Returns the new function.
|
||||
*/
|
||||
export function rearg<F extends (...args: any[]) => any>(
|
||||
func: F,
|
||||
...indexes: Array<number | number[]>
|
||||
): (...args: any[]) => ReturnType<F> {
|
||||
const flattenIndexes = flatten(indexes);
|
||||
|
||||
return function (this: any, ...args: any[]) {
|
||||
const reorderedArgs: any[] = flattenIndexes.map(i => args[i]).slice(0, args.length);
|
||||
|
||||
for (let i = reorderedArgs.length; i < args.length; i++) {
|
||||
reorderedArgs.push(args[i]);
|
||||
}
|
||||
|
||||
return func.apply(this, reorderedArgs);
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user