feat(times): Add times (#656)
Some checks are pending
CI / codecov (push) Waiting to run
Release / release (push) Waiting to run

This commit is contained in:
Dayong Lee 2024-10-05 22:17:43 +09:00 committed by GitHub
parent 42a4b9424b
commit 9edacf776f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 113 additions and 0 deletions

View File

@ -0,0 +1,16 @@
import { bench, describe } from 'vitest';
import { times as timesCompatToolkit_ } from 'es-toolkit/compat';
import { times as timesLodash_ } from 'lodash';
const timesCompatToolkit = timesCompatToolkit_;
const timesLodash = timesLodash_;
describe('times', () => {
bench('es-toolkit/compat/times', () => {
timesCompatToolkit(1000, i => i * 2);
});
bench('lodash/times', () => {
timesLodash(1000, i => i * 2);
});
});

View File

@ -0,0 +1,3 @@
export function doubled(n: number) {
return n * 2;
}

View File

@ -0,0 +1,3 @@
export function stubArray() {
return [];
}

View File

@ -149,3 +149,4 @@ export { toNumber } from './util/toNumber.ts';
export { toInteger } from './util/toInteger.ts';
export { toFinite } from './util/toFinite.ts';
export { eq } from './util/eq.ts';
export { times } from './util/times.ts';

View File

@ -0,0 +1,58 @@
import { describe, expect, it } from 'vitest';
import { times } from './times';
import { doubled } from '../_internal/doubled';
import { falsey } from '../_internal/falsey';
import { slice } from '../_internal/slice';
import { stubArray } from '../_internal/stubArray';
describe('times', () => {
it('should coerce non-finite `n` values to `0`', () => {
[-Infinity, NaN, Infinity].forEach(n => {
expect(times(n)).toEqual([]);
});
});
it('should coerce `n` to an integer', () => {
const actual = times(2.6, n => n);
expect(actual).toEqual([0, 1]);
});
it('should provide correct `iteratee` arguments', () => {
let args: any;
times(1, function () {
// eslint-disable-next-line @typescript-eslint/no-unused-expressions, prefer-rest-params
args || (args = slice.call(arguments));
});
expect(args).toEqual([0]);
});
it('should use `_.identity` when `iteratee` is nullish', () => {
// eslint-disable-next-line no-sparse-arrays
const values = [, null, undefined];
const expected = values.map(() => [0, 1, 2]);
const actual = values.map((value, index) => (index ? times(3, value as any) : times(3)));
expect(actual).toEqual(expected);
});
it('should return an array of the results of each `iteratee` execution', () => {
expect(times(3, doubled)).toEqual([0, 2, 4]);
});
it('should return an empty array for falsey and negative `n` values', () => {
const values = falsey.concat(-1, -Infinity);
const expected = values.map(stubArray);
const actual = values.map((value, index) => (index ? times(value as any) : times()));
expect(actual).toEqual(expected);
});
it('should return an empty array when `n > Number.MAX_SAFE_INTEGER`', () => {
expect(times(Number.MAX_SAFE_INTEGER + 1)).toEqual([]);
expect(times(Number.MAX_VALUE, doubled)).toEqual([]);
});
});

32
src/compat/util/times.ts Normal file
View File

@ -0,0 +1,32 @@
import { toInteger } from './toInteger';
/**
* Invokes the iteratee n times, returning an array of the results of each invocation.
*
* The iteratee is invoked with one argument; (index).
*
* @template F The type of the iteratee function.
* @param {number} n - The number of times to invoke iteratee.
* @param {F extends (n: number) => any} [iteratee] - The function invoked per iteration. Default is identity.
* @returns {Array<ReturnType<F>>} - Returns the array of results.
*
* @example
* times(3, doubled); // => [0, 2, 4]
* times(4); // => [0, 1, 2, 3]
* times(2, () => 'es-toolkit') // => ['es-toolkit', 'es-toolkit']
*/
export function times<F extends (n: number) => any>(n?: number, iteratee?: F): Array<ReturnType<F>> {
n = toInteger(n);
if (n < 1 || !Number.isSafeInteger(n)) {
return [];
}
const result = new Array(n);
for (let i = 0; i < n; i++) {
result[i] = typeof iteratee === 'function' ? iteratee(i) : i;
}
return result;
}