mirror of
https://github.com/toss/es-toolkit.git
synced 2024-11-24 03:32:58 +03:00
feat(sortBy): implement es-toolkit/sortBy
(#381)
* Implement sortBy * Add bench * Extends template from object * Fix example * Add mixed iteratees * Add docs and fix examples * Fix jsdoc * make prettier * Update src/array/sortBy.ts --------- Co-authored-by: Sojin Park <raon0211@gmail.com>
This commit is contained in:
parent
8310cd9d5d
commit
21a0ceabc5
22
benchmarks/performance/sortBy.bench.ts
Normal file
22
benchmarks/performance/sortBy.bench.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { bench, describe } from 'vitest';
|
||||
import { sortBy as sortByToolkit } from 'es-toolkit';
|
||||
import { sortBy as sortByLodash } from 'lodash';
|
||||
|
||||
describe('sortBy', () => {
|
||||
const users = [
|
||||
{ user: 'fred', age: 48, nested: { user: 'fred' } },
|
||||
{ user: 'barney', age: 34, nested: { user: 'barney' } },
|
||||
{ user: 'fred', age: 40, nested: { user: 'fred' } },
|
||||
{ user: 'barney', age: 36, nested: { user: 'bar' } },
|
||||
];
|
||||
const keys: Array<keyof (typeof users)[0]> = ['user', 'age'];
|
||||
|
||||
bench('es-toolkit/sortBy', () => {
|
||||
sortByToolkit(users, keys);
|
||||
sortByToolkit(users, [user => user.user, user => user.age]);
|
||||
});
|
||||
bench('lodash/sortBy', () => {
|
||||
sortByLodash(users, keys);
|
||||
sortByLodash(users, [user => user.user, user => user.age]);
|
||||
});
|
||||
});
|
@ -87,6 +87,7 @@ function sidebar(): DefaultTheme.Sidebar {
|
||||
{ text: 'sampleSize', link: '/reference/array/sampleSize' },
|
||||
{ text: 'shuffle', link: '/reference/array/shuffle' },
|
||||
{ text: 'size (compat)', link: '/reference/compat/array/size' },
|
||||
{ text: 'sortBy', link: '/reference/array/sortBy' },
|
||||
{ text: 'take', link: '/reference/array/take' },
|
||||
{ text: 'takeWhile', link: '/reference/array/takeWhile' },
|
||||
{ text: 'takeRight', link: '/reference/array/takeRight' },
|
||||
|
@ -95,6 +95,7 @@ function sidebar(): DefaultTheme.Sidebar {
|
||||
{ text: 'sampleSize', link: '/ko/reference/array/sampleSize' },
|
||||
{ text: 'shuffle', link: '/ko/reference/array/shuffle' },
|
||||
{ text: 'size (호환성)', link: '/ko/reference/compat/array/size' },
|
||||
{ text: 'sortBy', link: '/ko/reference/array/sortBy' },
|
||||
{ text: 'take', link: '/ko/reference/array/take' },
|
||||
{ text: 'takeWhile', link: '/ko/reference/array/takeWhile' },
|
||||
{ text: 'takeRight', link: '/ko/reference/array/takeRight' },
|
||||
|
47
docs/ko/reference/array/sortBy.md
Normal file
47
docs/ko/reference/array/sortBy.md
Normal file
@ -0,0 +1,47 @@
|
||||
# sortBy
|
||||
|
||||
주어진 `iteratees` (또는 키)에 따라 객체 배열을 오름차순으로 정렬해요.
|
||||
|
||||
이 함수는 객체 배열, 정렬할 기준이 되는 iteratee (또는 키)의 배열을 받아요.
|
||||
오름차순으로 정렬된 객체 배열을 반환해요.
|
||||
`iteratees`가 객체의 키일 경우엔 해당 키에 해당하는 값을 기준으로 정렬해요.
|
||||
`iteratees`가 `iteratee` 함수일 경우엔 해당 함수의 반환값을 기준으로 정렬해요.
|
||||
키의 값이 동일한 경우 다음 키를 기준으로 정렬 순서를 결정해요.
|
||||
|
||||
> `iteratee` 함수는 객체를 매개변수로 받고 값을 반환하는 함수에요.
|
||||
|
||||
## 인터페이스
|
||||
|
||||
```typescript
|
||||
function sortBy<T extends object>(collection: T[], iteratees: Array<Iteratee<T> | keyof T>): T[];
|
||||
```
|
||||
|
||||
### 파라미터
|
||||
|
||||
- `collection` (`T[]`): 정렬할 객체 배열.
|
||||
- `iteratees` (`Array<Iteratee<T> | keyof T>`): 정렬할 기준이 되는 iteratee 또는 키의 배열.
|
||||
|
||||
### 반환 값
|
||||
|
||||
(`T[]`) 정렬된 배열.
|
||||
|
||||
## 예시
|
||||
|
||||
```typescript
|
||||
const users = [
|
||||
{ user: 'foo', age: 24 },
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'foo ', age: 8 },
|
||||
{ user: 'bar ', age: 29 },
|
||||
];
|
||||
|
||||
sortBy(users, ['user', 'age']);
|
||||
sortBy(users, [obj => obj.user, 'age']);
|
||||
// results will be:
|
||||
// [
|
||||
// { user : 'bar', age: 7 },
|
||||
// { user : 'bar', age: 29 },
|
||||
// { user : 'foo', age: 8 },
|
||||
// { user : 'foo', age: 24 },
|
||||
// ]
|
||||
```
|
47
docs/reference/array/sortBy.md
Normal file
47
docs/reference/array/sortBy.md
Normal file
@ -0,0 +1,47 @@
|
||||
# sortBy
|
||||
|
||||
Sorts an array of objects based on the given `iteratees` (or keys) in ascending order.
|
||||
|
||||
This function takes an array of objects, an array of iteratees (or keys) to sort by.
|
||||
It returns the ascendingly sorted array of objects.
|
||||
If `iteratees` are keys of the object, it sorts based on the values of the keys.
|
||||
If `iteratees` are iteratee functions, it sorts based on the return values of the functions.
|
||||
If values for a key are equal, it moves to the next key to determine the order.
|
||||
|
||||
> An `iteratee` is a function that takes an object and returns a value.
|
||||
|
||||
## Signature
|
||||
|
||||
```typescript
|
||||
function sortBy<T extends object>(collection: T[], iteratees: Array<Iteratee<T>> | Array<keyof T>): T[];
|
||||
```
|
||||
|
||||
### Parameters
|
||||
|
||||
- `collection` (`T[]`): The array of objects to be sorted.
|
||||
- `iteratees` (`Array<Iteratee<T>> | Array<keyof T>`): The array of iteratees or keys to sort by.
|
||||
|
||||
### Returns
|
||||
|
||||
(`T[]`) The ascendingly sorted array of objects.
|
||||
|
||||
## Examples
|
||||
|
||||
```typescript
|
||||
const users = [
|
||||
{ user: 'foo', age: 24 },
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'foo ', age: 8 },
|
||||
{ user: 'bar ', age: 29 },
|
||||
];
|
||||
|
||||
sortBy(users, ['user', 'age']);
|
||||
sortBy(users, [obj => obj.user, obj => obj.age]);
|
||||
// results will be:
|
||||
// [
|
||||
// { user : 'bar', age: 7 },
|
||||
// { user : 'bar', age: 29 },
|
||||
// { user : 'foo', age: 8 },
|
||||
// { user : 'foo', age: 24 },
|
||||
// ]
|
||||
```
|
@ -22,6 +22,7 @@ export { maxBy } from './maxBy.ts';
|
||||
export { minBy } from './minBy.ts';
|
||||
export { orderBy } from './orderBy.ts';
|
||||
export { partition } from './partition.ts';
|
||||
export { sortBy } from './sortBy.ts';
|
||||
export { sample } from './sample.ts';
|
||||
export { sampleSize } from './sampleSize.ts';
|
||||
export { shuffle } from './shuffle.ts';
|
||||
|
56
src/array/sortBy.spec.ts
Normal file
56
src/array/sortBy.spec.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { sortBy } from './sortBy';
|
||||
|
||||
describe('sortBy', () => {
|
||||
const users = [
|
||||
{ user: 'foo', age: 24 },
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'foo', age: 8 },
|
||||
{ user: 'bar', age: 29 },
|
||||
];
|
||||
|
||||
it('should stable sort objects by a single property in ascending order', () => {
|
||||
expect(sortBy(users, ['user'])).toEqual([
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'bar', age: 29 },
|
||||
{ user: 'foo', age: 24 },
|
||||
{ user: 'foo', age: 8 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should stable sort objects by multiple properties', () => {
|
||||
expect(sortBy(users, ['user', 'age'])).toEqual([
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'bar', age: 29 },
|
||||
{ user: 'foo', age: 8 },
|
||||
{ user: 'foo', age: 24 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should stable sort objects by iteratee function', () => {
|
||||
expect(sortBy(users, [user => user.user])).toEqual([
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'bar', age: 29 },
|
||||
{ user: 'foo', age: 24 },
|
||||
{ user: 'foo', age: 8 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should stable sort objects by iteratee function and property', () => {
|
||||
expect(sortBy(users, [user => user.user, user => user.age])).toEqual([
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'bar', age: 29 },
|
||||
{ user: 'foo', age: 8 },
|
||||
{ user: 'foo', age: 24 },
|
||||
]);
|
||||
});
|
||||
|
||||
it('should stable sort objects by mixed iteratee function and key', () => {
|
||||
expect(sortBy(users, ['user', user => user.age])).toEqual([
|
||||
{ user: 'bar', age: 7 },
|
||||
{ user: 'bar', age: 29 },
|
||||
{ user: 'foo', age: 8 },
|
||||
{ user: 'foo', age: 24 },
|
||||
]);
|
||||
});
|
||||
});
|
65
src/array/sortBy.ts
Normal file
65
src/array/sortBy.ts
Normal file
@ -0,0 +1,65 @@
|
||||
type Iteratee<T> = (object: T) => T[keyof T];
|
||||
|
||||
/**
|
||||
* Sorts an array of objects based on the given iteratees or keys in ascending order.
|
||||
*
|
||||
* This function takes an array of objects, an array of iteratees (or keys) to sort by.
|
||||
* It returns the ascendingly sorted array of objects.
|
||||
* If `iteratees` are keys of the object, it sorts based on the values of the keys.
|
||||
* If `iteratees` are iteratee functions, it sorts based on the return values of the functions.
|
||||
* If values for a key are equal, it moves to the next key to determine the order.
|
||||
*
|
||||
* @template T - The type of the objects in the array.
|
||||
* @param {T[]} collection - The array of objects to be sorted.
|
||||
* @param {Array<Iteratee<T> | keyof T>} iteratees - The array of iteratees or keys to sort by.
|
||||
* @returns {T[]} The ascendingly sorted array of objects.
|
||||
*
|
||||
* @example
|
||||
* const users = [
|
||||
* { user: 'foo', age: 24 },
|
||||
* { user: 'bar', age: 7 },
|
||||
* { user: 'foo ', age: 8 },
|
||||
* { user: 'bar ', age: 29 },
|
||||
* ];
|
||||
*
|
||||
* sortBy(users, ['user', 'age']);
|
||||
* sortBy(users, [obj => obj.user, 'age']);
|
||||
* // results will be:
|
||||
* // [
|
||||
* // { user : 'bar', age: 7 },
|
||||
* // { user : 'bar', age: 29 },
|
||||
* // { user : 'foo', age: 8 },
|
||||
* // { user : 'foo', age: 24 },
|
||||
* // ]
|
||||
*/
|
||||
export function sortBy<T extends object>(collection: T[], iteratees: Array<Iteratee<T> | keyof T>): T[] {
|
||||
const compareValues = (a: T[keyof T], b: T[keyof T]) => {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (a > b) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
return collection.slice().sort((a, b) => {
|
||||
for (let i = 0; i < iteratees.length; i++) {
|
||||
const iteratee = iteratees[i];
|
||||
const iterateeIsFunction = typeof iteratee === 'function';
|
||||
|
||||
const valueA = iterateeIsFunction ? iteratee(a) : a[iteratee];
|
||||
const valueB = iterateeIsFunction ? iteratee(b) : b[iteratee];
|
||||
|
||||
const result = compareValues(valueA, valueB);
|
||||
|
||||
if (result !== 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user