-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
178 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { orderByRules } from './orderByRules' | ||
|
||
const strData = ['hello', 'fjc', '20', '花间一壶酒', '='] | ||
|
||
const numData = [-5, 4, 0, 1.2, 20] | ||
|
||
const arrData = [ | ||
{ a: 'x', b: 3 }, | ||
{ a: 'y', b: 4 }, | ||
{ a: 'x', b: 1 }, | ||
{ a: 'z', b: 1 }, | ||
{ a: 'y', b: 2 }, | ||
] | ||
|
||
describe('orderByRules', () => { | ||
test('desc 正常', () => { | ||
expect( | ||
orderByRules(strData, { | ||
iteratee: item => item.length, | ||
type: 'desc', | ||
}), | ||
).toEqual(['hello', '花间一壶酒', 'fjc', '20', '=']) | ||
|
||
expect( | ||
orderByRules(numData, { | ||
iteratee: item => item, | ||
type: 'desc', | ||
}), | ||
).toEqual([20, 4, 1.2, 0, -5]) | ||
|
||
expect( | ||
orderByRules(arrData, { | ||
iteratee: item => item.b, | ||
type: 'desc', | ||
}), | ||
).toEqual([ | ||
{ a: 'y', b: 4 }, | ||
{ a: 'x', b: 3 }, | ||
{ a: 'y', b: 2 }, | ||
{ a: 'x', b: 1 }, | ||
{ a: 'z', b: 1 }, | ||
]) | ||
}) | ||
|
||
test('asc 正常', () => { | ||
expect( | ||
orderByRules(strData, { | ||
iteratee: item => item.length, | ||
type: 'asc', | ||
}), | ||
).toEqual(['=', '20', 'fjc', 'hello', '花间一壶酒']) | ||
|
||
expect( | ||
orderByRules(numData, { | ||
iteratee: item => item, | ||
type: 'asc', | ||
}), | ||
).toEqual([-5, 0, 1.2, 4, 20]) | ||
|
||
expect( | ||
orderByRules(arrData, { | ||
iteratee: item => item.b, | ||
type: 'asc', | ||
}), | ||
).toEqual([ | ||
{ a: 'x', b: 1 }, | ||
{ a: 'z', b: 1 }, | ||
{ a: 'y', b: 2 }, | ||
{ a: 'x', b: 3 }, | ||
{ a: 'y', b: 4 }, | ||
]) | ||
}) | ||
|
||
test('多个规则正常', () => { | ||
expect( | ||
orderByRules(arrData, [ | ||
{ | ||
iteratee: item => item.b, | ||
type: 'desc', | ||
}, | ||
{ | ||
iteratee: item => item.a.charCodeAt(0), | ||
type: 'asc', | ||
}, | ||
]), | ||
).toEqual([ | ||
{ a: 'x', b: 3 }, | ||
{ a: 'x', b: 1 }, | ||
{ a: 'y', b: 4 }, | ||
{ a: 'y', b: 2 }, | ||
{ a: 'z', b: 1 }, | ||
]) | ||
|
||
expect( | ||
orderByRules(arrData, [ | ||
{ | ||
iteratee: item => item.b, | ||
type: 'desc', | ||
}, | ||
{ | ||
iteratee: item => item.a.charCodeAt(0), | ||
type: 'desc', | ||
}, | ||
]), | ||
).toEqual([ | ||
{ a: 'z', b: 1 }, | ||
{ a: 'y', b: 4 }, | ||
{ a: 'y', b: 2 }, | ||
{ a: 'x', b: 3 }, | ||
{ a: 'x', b: 1 }, | ||
]) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { castArray } from 'lodash-uni' | ||
import { OneOrMore } from '../types' | ||
|
||
export type OrderByRulesRule<T> = { | ||
/** | ||
* 迭代函数。 | ||
* | ||
* @param item 项目 | ||
* @returns 返回参与排序计算的值 | ||
*/ | ||
iteratee: (item: T) => any | ||
/** | ||
* 类型。 | ||
*/ | ||
type: 'asc' | 'desc' | ||
} | ||
|
||
/** | ||
* 允许指定一个或多个规则对数据进行排序。 | ||
* | ||
* @param data 要排序的数据 | ||
* @param rules 一个或多个规则 | ||
* @returns 返回排序后的数据 | ||
* @example | ||
* ```ts | ||
* orderByRules( | ||
* ['x', 'xyz', 'xy'], | ||
* { | ||
* iteratee: item => item.length, | ||
* type: 'desc', | ||
* }, | ||
* ) | ||
* // => ['xyz', 'xy', 'x'] | ||
* ``` | ||
*/ | ||
export function orderByRules<T>( | ||
data: T[], | ||
rules: OneOrMore<OrderByRulesRule<T>>, | ||
): T[] { | ||
return castArray(rules).reduce<T[]>((orderedData, rule) => { | ||
const cachedKeys: T[] = [] | ||
const cachedValues: any[] = [] | ||
const cachedIteratee: OrderByRulesRule<T>['iteratee'] = item => { | ||
const index = cachedKeys.indexOf(item) | ||
if (index === -1) { | ||
const value = rule.iteratee(item) | ||
cachedKeys.push(item) | ||
cachedValues.push(value) | ||
return value | ||
} | ||
return cachedValues[index] | ||
} | ||
|
||
const isAsc = rule.type === 'asc' | ||
|
||
orderedData.sort((a, b) => { | ||
a = cachedIteratee(a) | ||
b = cachedIteratee(b) | ||
return a === b ? 0 : a > b ? (isAsc ? 1 : -1) : isAsc ? -1 : 1 | ||
}) | ||
|
||
return orderedData | ||
}, data.slice()) | ||
} |