perf(at): Improve performance and compatibility with lodash (#798)

* perf(at): Improve performance and compatibility with lodash

* Change the implementation to match `Array.prototype.at` implementation

* Avoid truncating numbers if they are already integers
This commit is contained in:
Filip Sobol 2024-11-10 07:10:03 +01:00 committed by GitHub
parent 894a645c49
commit c939d97322
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 10 deletions

View File

@ -6,24 +6,35 @@ const atToolkit = atToolkit_;
const atLodash = atLodash_;
describe('at', () => {
const data = ['a', 'b', 'c', 'd', 'e'];
const indices = [0, 2, -2, 1.5, -1.5];
bench('es-toolkit/at', () => {
atToolkit(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
atToolkit(data, indices);
});
bench('lodash/at', () => {
atLodash(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]);
atLodash(data, indices);
});
bench('Array.prototype.at', () => {
indices.map(i => data.at(i));
});
});
describe('at/largeArray', () => {
const largeArray = Array.from({ length: 10000 }, (_, i) => i);
const largeIndex = Array.from({ length: 1000 }, (_, i) => i * 2);
const largeData = Array.from({ length: 10000 }, (_, i) => i);
const largeIndices = Array.from({ length: 1000 }, (_, i) => i * 2);
bench('es-toolkit/at', () => {
atToolkit(largeArray, largeIndex);
atToolkit(largeData, largeIndices);
});
bench('lodash/at', () => {
atLodash(largeArray, largeIndex);
atLodash(largeData, largeIndices);
});
bench('Array.prototype.at', () => {
largeIndices.map(i => largeData.at(i));
});
});

View File

@ -13,10 +13,17 @@ describe('at', () => {
});
it('should return `undefined` for nonexistent keys', () => {
expect(at(['a', 'b', 'c'], [2, 4, 0])).toEqual(['c', undefined, 'a']);
expect(at(['a', 'b', 'c'], [2, 4, 0, -4])).toEqual(['c', undefined, 'a', undefined]);
});
it('should return an empty array when no keys are given', () => {
expect(at(['a', 'b', 'c'], [])).toEqual([]);
});
it('should return undefined for non-integer indices', () => {
const data = ['a', 'b', 'c'];
const indices = [1.5, -1.5, NaN, Infinity, -Infinity];
expect(at(data, indices)).toEqual(indices.map(i => data.at(i)));
});
});

View File

@ -14,12 +14,19 @@
* console.log(result); // [20, 40, 50]
*/
export function at<T>(arr: readonly T[], indices: number[]): Array<T | undefined> {
const result: Array<T | undefined> = new Array(indices.length);
const result = new Array<T | undefined>(indices.length);
const length = arr.length;
for (let i = 0; i < indices.length; i++) {
const index = indices[i];
let index = indices[i];
result[i] = arr.at(index);
index = Number.isInteger(index) ? index : Math.trunc(index) || 0;
if (index < 0) {
index += length;
}
result[i] = arr[index];
}
return result;