这是indexloc提供的服务,不要输入任何密码
Skip to content

734 - Inclusive Range (🎥 Video Explanation and Solution) #25925

@dimitropoulos

Description

@dimitropoulos

734 - Inclusive Range

Inclusive Range might be one of the most complex of all of the challenges. It's very deserving of the extreme title. What's funny is that in a regular programming language it'd be very trivial: but in TypeScript: you hit on TypeScript's weakest abilities: dealing with big tuples and doing math.

🎥 Video Explanation

Release Date: 2023-05-15 19:00 UTC

Inclusive Range

🔢 Code

// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'

type A1 = InclusiveRange<200, 1>;
type B1 = [];
type C1 = Expect<Equal<A1, B1>>;

type A2 = InclusiveRange<10, 5>;
type B2 = [];
type C2 = Expect<Equal<A2, B2>>;

type A3 = InclusiveRange<5, 5>;
type B3 = [5];
type C3 = Expect<Equal<A3, B3>>;

type A4 = InclusiveRange<0, 10>;
type B4 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
type C4 = Expect<Equal<A4, B4>>;

type A5 = InclusiveRange<1, 200>;
type B5 = [
  1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
  11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
  21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
  31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
  51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
  61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
  71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
  81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
  91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
  101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
  111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
  121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
  131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
  141, 142, 143, 144, 145, 146, 147, 148, 149, 150,
  151, 152, 153, 154, 155, 156, 157, 158, 159, 160,
  161, 162, 163, 164, 165, 166, 167, 168, 169, 170,
  171, 172, 173, 174, 175, 176, 177, 178, 179, 180,
  181, 182, 183, 184, 185, 186, 187, 188, 189, 190,
  191, 192, 193, 194, 195, 196, 197, 198, 199, 200,
];
type C5 = Expect<Equal<A5, B5>>;

type A6 = InclusiveRange<22, 146>;
type B6 = [
      22, 23, 24, 25, 26, 27, 28, 29, 30,
  31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
  41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
  51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
  61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
  71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
  81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
  91, 92, 93, 94, 95, 96, 97, 98, 99, 100,
  101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
  111, 112, 113, 114, 115, 116, 117, 118, 119, 120,
  121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
  131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
  141, 142, 143, 144, 145, 146,
];
type C6 = Expect<Equal<A6, B6>>;

// ============== Alternative ==============
// @wotsushi
type InclusiveRange<
  Lower extends number,
  Higher extends number,
  C extends 1[] = [],
  I = false,
  R extends number[] = [],
  Count = C["length"]
> =
  I extends true
  ? Count extends Higher
    ? [...R, Higher]
    : InclusiveRange<
        Lower,
        Higher,
        [...C, 1],
        true,
        [...R, C["length"]]
      >
  : Count extends Lower
    ? InclusiveRange<Lower, Higher, C, true>
    : Count extends Higher
      ? []
      : InclusiveRange<Lower, Higher, [...C, 1], false>;

// ============== Alternative ==============
// @teamhcong
type InclusiveRange<
  Lower extends number,
  Higher extends number,
  
  // [0, 1, 2, 3, ... Higher]
  Count extends 1[] = CountToLower<`${Lower}`, `${Higher}`>,

  // [Lower, ..., Higher]
  Result extends number[] = [],

  // 0, 1, 2, 3, ... Higher
  C extends number = Count['length'],
> =
  [Count] extends [never]
  ? []
  : C extends Higher
    ? [...Result, C]
    : InclusiveRange<
        Lower,
        Higher,
        [...Count, 1],
        [...Result, C]
      >

// return `never` if Higher < Lower,
// otherwise return `[1, 1, 1, ...x Lower]`
type CountToLower<
  L extends string,
  H extends string,
  Count extends 1[] = []
> =
  L extends `${infer FirstL}${infer SecondL}${infer RestL}`
  ? H extends `${string}${infer SecondH}${infer RestH}`
    ? CountToLower<
        `${SecondL}${RestL}`,
        `${SecondH}${RestH}`,
        N<Count>[keyof N & FirstL]
      >
    : never
  : N<Count>[keyof N & L] extends
      [...N<Count>[keyof N & H], 1, ...1[]]
    ? never
    : N<Count>[keyof N & L]

// T for ten digit, '0' for single digit
type N<T extends 1[] = []> = {
  '0': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T],
  '1': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1],
  '2': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1],
  '3': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1],
  '4': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1, 1],
  '5': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1, 1, 1],
  '6': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1, 1, 1, 1],
  '7': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1, 1, 1, 1, 1],
  '8': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1, 1, 1, 1, 1, 1],
  '9': [...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, ...T, 1, 1, 1, 1, 1, 1, 1, 1, 1],
}

// ============== Alternative ==============
// @humandetail
type NumberToTuple<
  T extends number,
  Count extends 1[] = []
> =
  Count['length'] extends T
  ? Count
  : NumberToTuple<T, [...Count, 1]>

type MinusOne<T extends number> =
  NumberToTuple<T> extends [unknown, ...infer Tail]
  ? Tail['length']
  : 1

type PlusOne<T extends number> = [
  ...NumberToTuple<T>,
  1
]['length'] & number

type GreaterThan<A extends number, B extends number> =
  A extends B
  ? false
  : A extends 1
    ? false
    : B extends 1
      ? true
      : GreaterThan<MinusOne<A>, MinusOne<B>>

type InclusiveRange<
  Lower extends number,
  Higher extends number,
  Result extends number[] = []
> =
  GreaterThan<Lower, Higher> extends true
  ? Result
  : InclusiveRange<
      PlusOne<Lower>,
      Higher,
      [...Result, Lower]
    >

// ============== Alternative ==============
// @venusliang
type N1 = [any];
type N2 = [any, any];
type N3 = [any, any, any];
type N4 = [any, any, any, any];
type N5 = [any, any, any, any, any];
type N6 = [any, any, any, any, any, any];
type N7 = [any, any, any, any, any, any, any];
type N8 = [any, any, any, any, any, any, any, any];
type N9 = [any, any, any, any, any, any, any, any, any];
type N10 = [any, any, any, any, any, any, any, any, any, any];

type DigitNumToTuple<
  N,
  L = N extends string | number ? `${N}` : ''
> =
    L extends `${N1['length']}` ? N1
  : L extends `${N2['length']}` ? N2
  : L extends `${N3['length']}` ? N3
  : L extends `${N4['length']}` ? N4
  : L extends `${N5['length']}` ? N5
  : L extends `${N6['length']}` ? N6
  : L extends `${N7['length']}` ? N7
  : L extends `${N8['length']}` ? N8
  : L extends `${N9['length']}` ? N9
  : L extends `${N10['length']}` ? N10
  : [];

type AddTen<T extends any[]> = [
  [...T, ...N1]['length'],
  [...T, ...N2]['length'],
  [...T, ...N3]['length'],
  [...T, ...N4]['length'],
  [...T, ...N5]['length'],
  [...T, ...N6]['length'],
  [...T, ...N7]['length'],
  [...T, ...N8]['length'],
  [...T, ...N9]['length'],
  [...T, ...N10]['length']
];

type CumulativeTuple<T extends any[], L extends any[]> =
  L extends [...N10, ...infer O] ? [...AddTen<T>, ...CumulativeTuple<[...T, ...N10], O>] :
  L extends N9 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length'], [...T, ...N4]['length'], [...T, ...N5]['length'], [...T, ...N6]['length'], [...T, ...N7]['length'], [...T, ...N8]['length'], [...T, ...N9]['length']] :
  L extends N8 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length'], [...T, ...N4]['length'], [...T, ...N5]['length'], [...T, ...N6]['length'], [...T, ...N7]['length'], [...T, ...N8]['length']] :
  L extends N7 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length'], [...T, ...N4]['length'], [...T, ...N5]['length'], [...T, ...N6]['length'], [...T, ...N7]['length']] :
  L extends N6 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length'], [...T, ...N4]['length'], [...T, ...N5]['length'], [...T, ...N6]['length']] :
  L extends N5 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length'], [...T, ...N4]['length'], [...T, ...N5]['length']] :
  L extends N4 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length'], [...T, ...N4]['length']] :
  L extends N3 ? [[...T, ...N1]['length'], [...T, ...N2]['length'], [...T, ...N3]['length']] :
  L extends N2 ? [[...T, ...N1]['length'], [...T, ...N2]['length']] :
  L extends N1 ? [[...T, ...N1]['length']] : [];

// tuple repeat: [1], 3  => [1,1,1]
type TupleRepeat<
  T extends any[],
  N extends any,
  L extends any[] = [any],
  NS = N extends string | number ? `${N}` : ''
> =
  NS extends '0'
  ? []
  : `${L['length']}` extends NS
    ? T
    : [...T, ...TupleRepeat<T, N, [...L, any]>];

// number to char tuple:  123 => ['1','2','3']
type NumToCharTuple<
  N extends number,
  S extends string = `${N}`
> =
  S extends ''
  ? []
  : S extends `${infer F}${infer O}`
    ? [F, ...NumToCharTuple<N, O>]
    : [];

// generate length tuple 
type GetLenTuple<
  Len extends number,
  LT extends any[] = NumToCharTuple<Len>,
  B extends any[] = [any]
> =
  LT extends [...infer O, infer F]
  ? [
      ...TupleRepeat<B, F>,
      ...GetLenTuple<Len, O, TupleRepeat<B, 10>>
    ]
  : []

// get number length
type GetNumLen<
  N extends number,
  S extends string = `${N}`,
  R extends any[] = []
> =
  S extends `${string}${infer O}`
  ? GetNumLen<N, O, [...R, any]>
  : R['length'];

type GetTupleDiff<
  L extends any[],
  R extends any[]
> =
  L extends [...R, ...infer O]
  ? O
  : R extends [...L, ...infer O]
    ? O
    : [];

type TupleLenComparator<
  L extends any[],
  R extends any[]
> =
  L extends [...R, ...infer O]
  ? O['length'] extends 0
    ? 0
    : 1
  : -1;

type TupleAddRangeTuple<
  T extends any[],
  H extends any[],
  L extends any[] = GetTupleDiff<T, H>
> = CumulativeTuple<T, L>;

type InclusiveRange<
  Lower extends number,
  Higher extends number
> =
  Lower extends Higher
  ? [Lower]
  : TupleLenComparator<
        DigitNumToTuple<GetNumLen<Lower>>,
        DigitNumToTuple<GetNumLen<Higher>>
      > extends 1
    ? []
    : [
        Lower,
        ...TupleAddRangeTuple<
             GetLenTuple<Lower>,
             GetLenTuple<Higher>
           >
      ];

➕ More Solutions

For more video solutions to other challenges: see the umbrella list! #21338

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions