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

216 - Slice (🎥 Video Explanation and Solution) #25082

@dimitropoulos

Description

@dimitropoulos

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

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

Slice

🔢 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

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