feat(orderBy): Add orderBy (#123)

* feat(orderBy): add orderBy function

* feat(orderBy): add orderBy test code

* feat(orderBy): add orderBy bench

* feat(orderBy): add orderBy function docs

* feat(orderBy): add orderBy vitepress docs

* fix: test function & add the extend orders feature

* Update src/array/orderBy.ts

---------

Co-authored-by: Sojin Park <raon0211@gmail.com>
Co-authored-by: Sojin Park <raon0211@toss.im>
This commit is contained in:
hanna 2024-07-05 10:11:56 +09:00 committed by GitHub
parent 1918eec3d9
commit 1eada4d85d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 250 additions and 1 deletions

View File

@ -0,0 +1,25 @@
import { bench, describe } from 'vitest';
import { orderBy as orderByToolkit } from 'es-toolkit';
import { orderBy as orderByLodash } from 'lodash';
describe('orderBy', () => {
bench('es-toolkit/orderBy', () => {
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
orderByToolkit(users, ['user', 'age'], ['asc', 'asc']);
});
bench('lodash/orderBy', () => {
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
orderByLodash(users, ['user', 'age'], ['asc', 'asc']);
});
});

View File

@ -66,6 +66,7 @@ function sidebar(): DefaultTheme.Sidebar {
{ text: 'keyBy', link: '/reference/array/keyBy' },
{ text: 'minBy', link: '/reference/array/minBy' },
{ text: 'maxBy', link: '/reference/array/maxBy' },
{ text: 'orderBy', link: '/reference/array/orderBy' },
{ text: 'partition', link: '/reference/array/partition' },
{ text: 'sample', link: '/reference/array/sample' },
{ text: 'sampleSize', link: '/reference/array/sampleSize' },

View File

@ -65,6 +65,7 @@ function sidebar(): DefaultTheme.Sidebar {
{ text: 'keyBy', link: '/ko/reference/array/keyBy' },
{ text: 'minBy', link: '/ko/reference/array/minBy' },
{ text: 'maxBy', link: '/ko/reference/array/maxBy' },
{ text: 'orderBy', link: '/ko/reference/array/orderBy' },
{ text: 'partition', link: '/ko/reference/array/partition' },
{ text: 'sample', link: '/ko/reference/array/sample' },
{ text: 'sampleSize', link: '/ko/reference/array/sampleSize' },

View File

@ -0,0 +1,43 @@
# orderBy
여러 속성과 해당 순서 방향에 따라 객체 배열을 정렬해요.
이 함수는 객체 배열, 정렬할 키의 배열, 그리고 정렬 방향의 배열을 받아요.
각 키에 대해 해당 방향('asc'는 오름차순, 'desc'는 내림차순)에 따라 정렬된 배열을 반환해요.
키의 값이 동일한 경우 다음 키를 기준으로 정렬 순서를 결정해요.
## Signature
```typescript
function orderBy<T>(collection: T[], keys: Array<keyof T>, orders: Order[]): T[];
```
### Parameters
- `collection` (`T[]`): 정렬할 객체 배열.
- `keys` (`Array<keyof T>`): 정렬할 키(속성) 배열.
- `orders` (`Order[]`): 각 키에 대한 정렬 방향 배열('asc'는 오름차순, 'desc'는 내림차순).
### Returns
(`T[]`) 정렬된 배열.
## Examples
```typescript
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
const result = orderBy(users, ['user', 'age'], ['asc', 'desc']);
// result will be:
// [
// { user: 'barney', age: 36 },
// { user: 'barney', age: 34 },
// { user: 'fred', age: 48 },
// { user: 'fred', age: 40 },
// ]
```

View File

@ -0,0 +1,44 @@
# orderBy
Sorts an array of objects based on multiple properties and their corresponding order directions.
This function takes an array of objects, an array of keys to sort by, and an array of order directions.
It returns the sorted array, ordering by each key according to its corresponding direction
('asc' for ascending or 'desc' for descending). If values for a key are equal,
it moves to the next key to determine the order.
## Signature
```typescript
function orderBy<T>(collection: T[], keys: Array<keyof T>, orders: Order[]): T[];
```
### Parameters
- `collection` (`T[]`): The array of objects to be sorted.
- `keys` (`Array<keyof T>`): An array of keys (properties) by which to sort.
- `orders` (`Order[]`): An array of order directions ('asc' for ascending or 'desc' for descending).
### Returns
(`T[]`) The sorted array.
## Examples
```typescript
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
const result = orderBy(users, ['user', 'age'], ['asc', 'desc']);
// result will be:
// [
// { user: 'barney', age: 36 },
// { user: 'barney', age: 34 },
// { user: 'fred', age: 48 },
// { user: 'fred', age: 40 },
// ]
```

View File

@ -9,7 +9,7 @@ export { dropRight } from './dropRight.ts';
export { dropRightWhile } from './dropRightWhile.ts';
export { dropWhile } from './dropWhile.ts';
export { fill } from './fill.ts';
export { forEachRight } from './forEachRight.ts'
export { forEachRight } from './forEachRight.ts';
export { groupBy } from './groupBy.ts';
export { intersection } from './intersection.ts';
export { intersectionBy } from './intersectionBy.ts';
@ -17,6 +17,7 @@ export { intersectionWith } from './intersectionWith.ts';
export { keyBy } from './keyBy.ts';
export { maxBy } from './maxBy.ts';
export { minBy } from './minBy.ts';
export { orderBy } from './orderBy.ts';
export { partition } from './partition.ts';
export { sample } from './sample.ts';
export { sampleSize } from './sampleSize.ts';

76
src/array/orderBy.spec.ts Normal file
View File

@ -0,0 +1,76 @@
import { describe, it, expect } from 'vitest';
import { orderBy } from './orderBy';
describe('orderBy', () => {
it('should order objects by a single property in ascending order', () => {
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
const result = orderBy(users, ['user'], ['asc']);
expect(result).toEqual([
{ user: 'barney', age: 34 },
{ user: 'barney', age: 36 },
{ user: 'fred', age: 48 },
{ user: 'fred', age: 40 },
]);
});
it('should order objects by a single property in descending order', () => {
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
const result = orderBy(users, ['user'], ['desc']);
expect(result).toEqual([
{ user: 'fred', age: 48 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 34 },
{ user: 'barney', age: 36 },
]);
});
it('should order objects by multiple properties', () => {
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 36 },
];
const result = orderBy(users, ['user', 'age'], ['asc', 'desc']);
expect(result).toEqual([
{ user: 'barney', age: 36 },
{ user: 'barney', age: 34 },
{ user: 'fred', age: 48 },
{ user: 'fred', age: 40 },
]);
});
it('should extend orders if orders length is less than keys length', () => {
const users = [
{ user: 'fred', age: 48 },
{ user: 'barney', age: 36 },
{ user: 'fred', age: 40 },
{ user: 'barney', age: 34 },
];
const result = orderBy(users, ['user', 'age'], ['asc']);
expect(result).toEqual([
{ user: 'barney', age: 34 },
{ user: 'barney', age: 36 },
{ user: 'fred', age: 40 },
{ user: 'fred', age: 48 },
]);
});
});

58
src/array/orderBy.ts Normal file
View File

@ -0,0 +1,58 @@
type Order = 'asc' | 'desc';
/**
* Sorts an array of objects based on multiple properties and their corresponding order directions.
*
* This function takes an array of objects, an array of keys to sort by, and an array of order directions.
* It returns the sorted array, ordering by each key according to its corresponding direction
* ('asc' for ascending or 'desc' for descending). If values for a key are equal,
* it moves to the next key to determine the order.
*
* @template T - The type of elements in the array.
* @param {T[]} collection - The array of objects to be sorted.
* @param {Array<keyof T>} keys - An array of keys (properties) by which to sort.
* @param {Order[]} orders - An array of order directions ('asc' for ascending or 'desc' for descending).
* @returns {T[]} - The sorted array.
*
* @example
* // Sort an array of objects by 'user' in ascending order and 'age' in descending order.
* const users = [
* { user: 'fred', age: 48 },
* { user: 'barney', age: 34 },
* { user: 'fred', age: 40 },
* { user: 'barney', age: 36 },
* ];
* const result = orderBy(users, ['user', 'age'], ['asc', 'desc']);
* // result will be:
* // [
* // { user: 'barney', age: 36 },
* // { user: 'barney', age: 34 },
* // { user: 'fred', age: 48 },
* // { user: 'fred', age: 40 },
* // ]
*/
export function orderBy<T>(collection: T[], keys: Array<keyof T>, orders: Order[]): T[] {
const compareValues = (a: T[keyof T], b: T[keyof T], order: Order) => {
if (a < b) {
return order === 'asc' ? -1 : 1;
}
if (a > b) {
return order === 'asc' ? 1 : -1;
}
return 0;
};
const effectiveOrders = keys.map((_, index) => orders[index] || orders[orders.length - 1]);
return collection.slice().sort((a, b) => {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const order = effectiveOrders[i];
const result = compareValues(a[key], b[key], order);
if (result !== 0) {
return result;
}
}
return 0;
});
}