TypeScript 杂记五 《Sort》
Posted 左手121
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript 杂记五 《Sort》相关的知识,希望对你有一定的参考价值。
TypeScript 杂记五 《Sort》
说明
Sort<[]> // []
Sort<[1]> // [1]
Sort<[2, 4, 7, 6, 6, 6, 5, 8, 9]> // [2, 4, 5, 6, 6, 6, 7, 8, 9]
Sort<[3, 2, 1], true> // [3, 2, 1]
Sort<[3, 2, 0, 1, 0, 0, 0], true> // [3, 2, 1, 0, 0, 0, 0]
扩展:支持 bigint 和 float
思路
- 先实现简单的整数,大致如下:
type IType = number;
type Sort<T extends IType[]> = Helper<T>;
- 默认升序,第二参数可以改成降序,大致如下:
type Reverse<T extends unknown[], RR extends unknown[] = []> = T extends [
...infer L,
infer R
]
? Reverse<L, [...RR, R]>
: RR;
type Sort<T extends IType[], D extends boolean = false> = D extends false
? Helper<T>
: Reverse<Helper<T>>;
- 只有数据长度大于 1 的时候才会触发排序,大致如下:
type Helper<T extends IType[]> = T extends [] | [IType] ? T : Run<T>;
- 这里采用冒泡排序的方式(实现简单),大致如下:
- Compare 用来比较两个数字的大小。返回 1 表示 B 小,则需要交换
- 每次获取数组的前两个进行比较,小的那个写入 R 中。大的继续下一次的运行
- 如果本次递归中发生过交换,那么重新执行一次,这个时候新的数据就是上一次的结果
- 直到没有发生过交换则返回结果
type Run<
T extends unknown[],
R extends unknown[] = [],
F extends boolean = false
> = T extends [infer A, infer B, ...infer C]
? Run<
[Compare<A, B> extends 1 ? A : B, ...C],
[...R, Compare<A, B> extends 1 ? B : A],
F extends true ? F : Compare<A, B> extends 1 ? true : false
>
: F extends true
? Run<[...R, T[0]]>
: [...R, T[0]];
- 比较函数的实现
- 如果两个数字是负数,则取整数部分比较,结果取反
- 如果两个数字是正数,则直接比较
- 如果 A 是负数,返回 -1
- 如果 B 是负数,返回 1
type Compare<A, B> = A extends IType
? B extends IType
? `$A` extends `-$infer AA`
? `$B` extends `-$infer BB`
? CompareHelper<AA, BB> extends 1
? -1
: CompareHelper<AA, BB> extends 0
? 0
: 1
: -1
: `$B` extends `-$infer BB`
? 1
: CompareHelper<`$A`, `$B`>
: -1
: -1;
- 实现具体的比较:
- H 的长度同时等于 A,B 则表示两个相等, 返回 0
- H 先等于 A,说明 A 大, 返回 1
- H 先等于 B,说明 B 大, 返回 -1
type CompareHelper<
A extends string,
B extends string,
H extends unknown[] = []
> = `$H["length"]` extends B
? `$H["length"]` extends A
? 0
: 1
: `$H["length"]` extends A
? -1
: CompareHelper<A, B, [...H, unknown]>;
最终结果
type IType = number;
type Reverse<T extends unknown[], RR extends unknown[] = []> = T extends [
...infer L,
infer R
]
? Reverse<L, [...RR, R]>
: RR;
type CompareHelper<
A extends string,
B extends string,
H extends unknown[] = []
> = `$H["length"]` extends B
? `$H["length"]` extends A
? 0
: 1
: `$H["length"]` extends A
? -1
: CompareHelper<A, B, [...H, unknown]>;
type Compare<A, B> = A extends IType
? B extends IType
? `$A` extends `-$infer AA`
? `$B` extends `-$infer BB`
? CompareHelper<AA, BB> extends 1
? -1
: CompareHelper<AA, BB> extends 0
? 0
: 1
: -1
: `$B` extends `-$infer BB`
? 1
: CompareHelper<`$A`, `$B`>
: -1
: -1;
type Run<
T extends unknown[],
R extends unknown[] = [],
F extends boolean = false
> = T extends [infer A, infer B, ...infer C]
? Run<
[Compare<A, B> extends 1 ? A : B, ...C],
[...R, Compare<A, B> extends 1 ? B : A],
F extends true ? F : Compare<A, B> extends 1 ? true : false
>
: F extends true
? Run<[...R, T[0]]>
: [...R, T[0]];
type Helper<T extends IType[]> = T extends [] | [IType] ? T : Run<T>;
type Sort<T extends IType[], D extends boolean = false> = D extends false
? Helper<T>
: Reverse<Helper<T>>;
type Test1 = Sort<[]>; // []
type Test2 = Sort<[1]>; // [1]
type Test3 = Sort<[2, 4, 7, 6, 6, 6, 5, 8, 9]>; // [2, 4, 5, 6, 6, 6, 7, 8, 9]
type Test4 = Sort<[3, 2, 1], true>; // [3, 2, 1]
type Test5 = Sort<[3, 2, 0, 1, 0, 0, 0], true>; // [3, 2, 1, 0, 0, 0, 0]
type Test6 = Sort<[2, -4, 7, 6, -6, 6, 5, 8, 9]>; // [-6, -4, 2, 5, 6, 6, 7, 8, 9]
type Test7 = Sort<[2, -4, 7, 6, -6, 6, 5, 8, 9], true>; // [9, 8, 7, 6, 6, 5, 2, -4, -6]
扩展 - bigint
- 首先将数字转换成字符串数组,大致如下:
type IType = number | bigint;
type StringToArray<
T,
RR extends string[] = []
> = T extends `$infer L$infer R` ? StringToArray<R, [...RR, L]> : RR;
// 这里改造一下,应为已经提前处理了负数,所以这里只会是正数
type Compare<A, B> = A extends string
? B extends string
? CompareHelper<A, B>
: -1
: -1;
type CompareArray<A, B> = A extends IType
? B extends IType
? `$A` extends `-$infer AA`
? `$B` extends `-$infer BB`
? CompareArrayHelper<StringToArray<AA>, StringToArray<BB>> extends 1
? -1
: CompareArrayHelper<StringToArray<AA>, StringToArray<BB>> extends 0
? 0
: 1
: -1
: `$B` extends `-$infer BB`
? 1
: CompareArrayHelper<StringToArray<`$A`>, StringToArray<`$B`>>
: -1
: -1;
- 比较两个数组
- 如果 A 的长度大于 B 则返回 -1
- 如果 B 的长度大于 A 则返回 1
- 长度一致,则从头开始比较两个数组的每一项
- 这里改造之前的结果
type CompareArrayHelper<
A extends string[],
B extends string[],
H extends unknown[] = []
> = H["length"] extends B["length"]
? H["length"] extends A["length"]
? CompareArrayHelperEqual<A, B>
: 1
: H["length"] extends A["length"]
? -1
: CompareArrayHelper<A, B, [...H, unknown]>;
- 比较数组的每一项
- 如果返回 0,则比较下一个数字
- 否则返回 Compare 的值
- 如果一直到结果都是没有返回结果则表示相等,返回 0
type CompareArrayHelperEqual<
A extends unknown[],
B extends unknown[]
> = A extends [infer AL, ...infer AR]
? B extends [infer BL, ...infer BR]
? Compare<AL, BL> extends 0
? CompareArrayHelperEqual<AR, BR>
: Compare<AL, BL>
: 0
: 0;
- 优化后的结果:
type IType = number | bigint;
type Reverse<T extends unknown[], RR extends unknown[] = []> = T extends [
...infer L,
infer R
]
? Reverse<L, [...RR, R]>
: RR;
type StringToAr以上是关于TypeScript 杂记五 《Sort》的主要内容,如果未能解决你的问题,请参考以下文章
TypeScript 杂记九 《Integers Comparator》
TypeScript 杂记九 《Integers Comparator》