-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Open
Description
216 - Slice
We have entered the era of 100+ line solutions. This may seem simple because it's something you could do relatively easily in JavaScript, but it's got quite a lot of moving pieces, no matter how you approach it.
🎥 Video Explanation
🔢 Code
// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'
type Arr = [1, 2, 3, 4, 5]
// basic
type A1 = Slice<Arr, 0, 1>;
type B1 = [1];
type C1 = Expect<Equal<A1, B1>>;
type A2 = Slice<Arr, 0, 0>;
type B2 = [];
type C2 = Expect<Equal<A2, B2>>;
type A3 = Slice<Arr, 2, 4>;
type B3 = [3, 4];
type C3 = Expect<Equal<A3, B3>>;
// optional args
type A4 = Slice<[]>;
type B4 = [];
type C4 = Expect<Equal<A4, B4>>;
type A5 = Slice<Arr>;
type B5 = Arr;
type C5 = Expect<Equal<A5, B5>>;
type A6 = Slice<Arr, 0>;
type B6 = Arr;
type C6 = Expect<Equal<A6, B6>>;
type A7 = Slice<Arr, 2>;
type B7 = [3, 4, 5];
type C7 = Expect<Equal<A7, B7>>;
// negative index
type A8 = Slice<Arr, 0, -1>;
type B8 = [1, 2, 3, 4];
type C8 = Expect<Equal<A8, B8>>;
type A9 = Slice<Arr, -3, -1>;
type B9 = [3, 4];
type C9 = Expect<Equal<A9, B9>>;
// invalid
type A10 = Slice<Arr, 10>;
type B10 = [];
type C10 = Expect<Equal<A10, B10>>;
type A11 = Slice<Arr, 1, 0>;
type B11 = [];
type C11 = Expect<Equal<A11, B11>>;
type A12 = Slice<Arr, 10, 20>;
type B12 = [];
type C12 = Expect<Equal<A12, B12>>;
// ============= Your Code Here =============
// zhaoyao91
/** if N is negative, convert it to its positive counterpart by the Arr */
type ToPositive<
N extends number,
Arr extends unknown[]
> =
`${N}` extends `-${infer P extends number}`
? Slice<Arr, P>['length']
: N
/** get the initial N items of Arr */
type InitialN<
Arr extends unknown[],
N extends number,
Acc extends unknown[] = []
> =
Acc['length'] extends N | Arr['length']
? Acc
: InitialN<Arr, N, [...Acc, Arr[Acc['length']]]>
type Slice<
T extends unknown[],
Start extends number = 0,
End extends number = T['length']
> =
InitialN<T, ToPositive<End, T>> extends [
...InitialN<T, ToPositive<Start, T>>,
...infer Rest,
]
? Rest
: [];
// ============== Alternative ==============
// @teamchong
type Slice<
T extends unknown[],
Start = 0,
End = T['length']
> =
[
FindIndex<T, Start>,
FindIndex<T, End>
] extends [
infer S extends number,
infer E extends number
]
? SliceFromStart<S, SliceFromEnd<T, E>>
: T
type FindIndex<T extends unknown[], Index> =
`${Index & number}` extends `-${string}`
? FindNegativeIndex<T, Index>
: FindPositiveIndex<T, Index>
type RemoveLast<T extends unknown[]> =
T extends [...infer Head, unknown]
? Head
: [];
type FindPositiveIndex<
T extends unknown[],
Index,
Count extends 1[] = []
> =
1 extends
| (T extends [] ? 1 : 0)
| (Index extends Count['length'] ? 1 : 0)
? Count['length']
: FindPositiveIndex<
RemoveLast<T>,
Index,
[...Count, 1]
>
type FindNegativeIndex<
T extends unknown[],
Index,
Count extends 1[] = []
> =
1 extends
| (T extends [] ? 1 : 0)
| (`${Index & number}` extends
`-${Count['length']}` ? 1 : 0)
? T['length']
: FindNegativeIndex<
RemoveLast<T>,
Index,
[...Count, 1]
>
type SliceFromEnd<T extends unknown[], End> =
T['length'] extends End
? T
: SliceFromEnd<
RemoveLast<T>,
End
>
type SliceFromStart<
Start,
Arr extends unknown[],
Count extends 1[] = []
> =
Count['length'] extends Start
? Arr
: SliceFromStart<
Start,
RemoveLast<Arr>,
[...Count, 1]
>
// ============== Alternative ==============
// @MajorLift
type IntADT = number | string | bigint;
type Signum<N extends IntADT> =
`${N}` extends '0'
? 0
: `${N}` extends `-${string}`
? -1
: 1;
type IsNegative<N extends IntADT> =
Signum<N> extends -1
? true
: false;
type IsNonNegative<N extends IntADT> =
IsNegative<N> extends false
? true
: false;
type Absolute<N extends number> =
`${N}` extends `-${infer R extends number}`
? R
: N;
type Shift<
T extends any[],
N extends number = 1
> =
N extends 0
? T
: T extends [unknown, ...infer Rest]
? Shift<Rest, Subtract<N, 1>>
: [];
type Pop<
T extends any[],
N extends number = 1
> =
N extends 0
? T
: T extends [...infer Rest, unknown]
? Pop<Rest, Subtract<N, 1>>
: [];
type Subtract<
M extends number,
S extends number
> =
Repeat<M> extends [...Repeat<S>, ...infer Rest]
? Rest["length"]
: never;
type Repeat<
N extends number,
T extends unknown = null,
M extends T[] = []
> =
M["length"] extends N
? M
: Repeat<N, T, [...M, T]>;
type LessThan<T extends number, U extends number> =
Equal<T, U> extends true
? false
: Subtract<T, U> extends never
? true
: false;
/**
* @returns true if I, J are not numbers
* or [I, J) is unbounded by [Acc[0], Acc[1])
*/
type OutOfBounds<
LO extends number | never,
HI extends number | never,
RANGE extends number[]
> =
LO extends never
? true
: HI extends never
? true
: LessThan<LO, RANGE[0]> extends true
? true
: LessThan<RANGE[1], HI> extends true
? true
: false;
/**
* @typedef Slice
* @params START_POS?, END_POS? - START, END converted to positive indices
* @returns T.slice(START_POS, END_POS)
*/
type Slice<
T extends unknown[],
START extends number = 0,
END extends number = T["length"],
START_POS extends number =
IsNonNegative<START> extends true
? START
: Subtract<T["length"], Absolute<START>>,
END_POS extends number =
IsNonNegative<END> extends true
? Subtract<T["length"], END>
: Absolute<END>,
RESULT =
OutOfBounds<
START_POS,
END_POS,
[0, T["length"]]
> extends true
? []
: Shift<Pop<T, END_POS>, START_POS>,
> = RESULT;➕ More Solutions
For more video solutions to other challenges: see the umbrella list! #21338
Metadata
Metadata
Assignees
Labels
No labels