TypeScript 杂记五 《Sort》

Posted 左手121

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了TypeScript 杂记五 《Sort》相关的知识,希望对你有一定的参考价值。

TypeScript 杂记五 《Sort》

说明

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》

TypeScript 杂记九 《Integers Comparator》

TypeScript 杂记十二 《Multiply》

TypeScript 杂记一

TypeScript 杂记一