-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Open
Description
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
🔢 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
Labels
No labels