04499-medium-chunk

Back

type Chunk<
  P extends any[],
  N extends number,
  A extends any[] = []
> = N extends keyof P
  ? N extends A['length']
    ? [A, ...Chunk<P, N>]
    : P extends [infer S, ...infer R]
    ? Chunk<R, N, [...A, S]>
    : [A] extends [[]]
    ? A
    : [A]
  : A

Solution by Keith-Web3 #35015

type Chunk<T extends any[], L extends number = 1, U extends any[] = []> = U['length'] extends L ? [U, ...Chunk<T, L>] :
T extends [infer R, ...infer rest] ? 
Chunk<rest, L, [...U, R]> : U extends [] ? U : [U]

Solution by ouzexi #34073

type Chunk<T extends any[],N extends number> =
T extends [] ? [] : // 1
T extends [infer L,infer M,...infer R] // 2
? L extends any[] // 3
? L['length'] extends N // 4
? [L,...Chunk<[M,...R],N>] // 5
: Chunk<[[...L,M],...R],N> // 6
: Chunk<[[L],...[M,...R]],N> // 7
: T[0] extends any[] // 8
?  T : [T] // 9

看了很多答案,似乎都是带了第二个参数的,其实没有必要。 逐行解释

T extends [] ? [] : 这句是为了判空 T extends [infer L,infer M,...infer R] 这句是关键,假设为了调整数组的大小,那么左边数组必须加入一个新参数,所以需要从右边借一个参数过来。那么问题来了 这个句子什么时候才会返回,看下面这个例子。

[1,2,3,4] extends  [infer L,infer M,...infer R] ? L | M | R : [] // 1 | 2 | [3,4]
[1,2,3] extends  [infer L,infer M,...infer R] ? L | M | R : [] // 1 | 2 | [3]
[1,2] extends  [infer L,infer M,...infer R] ? L | M | R  //2 | 1 | [] 说实在的这个联合类型顺序是怎么回事,我是一点都搞不懂,知道的大佬能说一下吗
[1] extends  [infer L,infer M,...infer R] ? L | M | R : [] // []

也就是说,只有当T参数大于一个的时候才会进入正确的通道。并获得参数L``M``R,然后来看这一句 L extends any[] 判断第一个参数是不是数组,如果不是说明是第一次进去,那么你就需要往L外面套上一层变成[L],所以需要第7行Chunk<[[L],...[M,...R]],N> // 7 。 当L是一个数组之后我们需要第4行 L['length'] extends N // 4来判断这个数组的长度是否等于N,不是的话就往左边加入新参数M继续遍历,也就是第6行: Chunk<[[...L,M],...R],N> // 6,如果说长度等于N的话,就可以进入下面的第5行了 [L,...Chunk<[M,...R],N>] // 5,继续往右遍历,直到T只剩下[最后一个参数],这时候数组不满足于第2行T extends [infer L,infer M,...infer R] // 2进入了第8行T[0] extends any[] // 8,判断第一个参数是不是数组,是的话就直接返回T,不是的话就往外面套一层变成[T]

不过笔者发现一个小bug就是了,你往里面放一个带数组的数组就会出现问题,如下

Chunk<[1, 2, [3, 4]], 2> // [[1, 2], [3, 4]]
Chunk<[1, 2, [3, 4]], 1> // [[1], [2], [3, 4]]

希望作者能完善一下样例和说明,毕竟上面这个不管怎么解释都有点说不太过去,我自己也不了解chunk的原理,所以也不知道这样划分对不对

Solution by xdrlmm #33957

// your answers
type Chunk<T extends any[], N extends number, Res extends any[] = [], C extends any[] = []> = 
  C['length'] extends N ? Chunk<T, N, [...Res, C]> : 
  T extends [infer A, ...infer R] ? Chunk<R, N, Res, [...C, A]> : C extends [] ? Res : [...Res, C]

Solution by heyuelan #33856

type Chunk<T extends any[], S extends number, Res extends any[] = [], Part extends any[] = [] > = 
 T extends [infer F, ...infer Rest] 
    ? S extends Part['length']
      ? Chunk<Rest, S, [...Res, Part], [F]>
      : Chunk<Rest, S, Res, [...Part, F]>
    : Res extends []
      ? Part extends []
        ? []
        : [Part]
      : [...Res, Part]

Solution by PiligrimStas #33752

type _Chunk<T extends any[], U extends number, R extends any[] = []> = T extends [infer F, ...infer rest]
  ? R['length'] extends U
    ? [R, ..._Chunk<rest, U, [F]>]
    : _Chunk<rest, U, [...R, F]>
  : [R]

type Chunk<T extends any[], U extends number> = T extends [] ? [] : _Chunk<T, U>

Solution by rimo030 #32886

// your answers
type Chunk<
	T extends any[],
	N extends number = 1,
	R extends any[] = [],
	C extends any[] = []
> = T extends [infer F, ...infer Rest]
	? C['length'] extends N
		? Chunk<Rest, N, [...R, C], [F]>
		: Chunk<Rest, N, R, [...C, F]>
	: [...R, ...(C['length'] extends 0 ? [] : [C])];

Solution by TRIS-H #31637

type Chunk<
  T extends any[],
  N extends number,
  Arr extends unknown[] = []
> = Arr["length"] extends N
  ? [Arr, ...Chunk<T, N>]
  : T extends [infer First, ...infer res]
  ? Chunk<res, N, [...Arr, First]>
  : Arr["length"] extends 0
  ? []
  : [Arr];

Solution by sunsunmonkey #31542

type NumberToArray<T extends number, U extends boolean[] = []> = 
  U['length'] extends T ?
  U :
  NumberToArray<T, [...U, true]>

type TakeFirst<T extends unknown[], S extends number, U extends unknown[] = []> = 
  U['length'] extends S ?
  U :
  T extends [infer F, ...infer Rest] ?
  TakeFirst<Rest, S, [...U, F]> :
  T

type PopFirst<T extends unknown[], S extends number, U extends unknown[] = []> = 
  U['length'] extends S ?
  T :
  T extends [infer _, ...infer Rest] ?
  PopFirst<Rest, S, [...U, true]> : 
  T

type WrapChunks<T extends unknown[], S extends number> = 
  PopFirst<T, S>['length'] extends 0 ?
  [T] :
  [TakeFirst<T, S>, ...Chunk<PopFirst<T, S>, S>]

type Chunk<T extends unknown[], S extends number> =
  T['length'] extends 0 ?
  [] :
  WrapChunks<T, S>

/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<Chunk<[], 1>, []>>,
  Expect<Equal<Chunk<[1, 2, 3], 1>, [[1], [2], [3]]>>,
  Expect<Equal<Chunk<[1, 2, 3], 2>, [[1, 2], [3]]>>,
  Expect<Equal<Chunk<[1, 2, 3, 4], 2>, [[1, 2], [3, 4]]>>,
  Expect<Equal<Chunk<[1, 2, 3, 4], 5>, [[1, 2, 3, 4]]>>,
  Expect<Equal<Chunk<[1, true, 2, false], 2>, [[1, true], [2, false]]>>,
]

Solution by gearonixx #30915

type Chunk<T extends unknown[], N extends number, C extends unknown[] = [], R extends unknown[] = []> = T extends [
  infer F,
  ...infer Rest,
]
  ? C['length'] extends N
    ? Chunk<Rest, N, [F], [...R, C]>
    : Chunk<Rest, N, [...C, F], [...R]>
  : [...R, C];

Solution by leejaehyup #30829

type Chunk<T extends readonly any[], N extends number, C extends any[] = [], R extends any[] = []> =
  C['length'] extends N
    ? Chunk<T, N, [], [...R, C]>
    : T extends [infer TF, ...infer TR]
      ? Chunk<TR, N, [...C, TF], R>
      : C extends []
        ? R
        : [...R, C]

Solution by matallui #30809

type Chunk<T extends any[], N extends number, C extends any[] = [], Result extends any[] = []> =
  C['length'] extends N
    ? Chunk<T, N, [], [...Result, C]>
    : T extends [infer F, ...infer Rest]
      ? Chunk<Rest, N, [...C, F], Result>
      : C extends []
        ? Result
        : [...Result, C]

Solution by jazelly #30452

// your answers,// 增加一个C记录chunk的结果
type Chunk<
	T extends unknown[],
	U extends number,
	C extends unknown[] = []
> = T extends [infer F, ...infer R]
	? Equal<C['length'], U> extends true
		? [C, ...Chunk<T, U, []>]
		: Chunk<R, U, [...C, F]>
	: C extends []
	? []
	: [C]

Solution by bebusy007 #30017

type Chunk<T extends any[], N extends number, A extends any[] = [], S extends any[] = []> =
  T extends [infer F, ...infer Rest]
    ? A['length'] extends N
      ? Chunk<Rest, N, [F], [...S, A]>
      : Chunk<Rest, N, [...A, F], S>
    : A['length'] extends 0 ? S : [...S, A]

Solution by hesoso #29841

type Chunk<
  Tuple extends unknown[],
  N extends number,
  Res extends unknown[] = [],
  Pack extends unknown[] = []
> = Tuple extends [infer Head, ...infer Tail]
  ? Pack["length"] extends N
    ? Chunk<Tail, N, [...Res, Pack], [Head]>
    : Chunk<Tail, N, Res, [...Pack, Head]>
  : Pack extends []
  ? Res
  : [...Res, Pack];

Solution by idebbarh #28842

type Pop<T extends any[], C extends number, S extends any[] = []> = S['length'] extends C
  ? S
  : T extends []
  ? S
  : T extends [infer First, ...infer Rest]
  ? Pop<Rest, C, [...S, First]>
  : never

type Chunk<T extends any[], C extends number> = T extends []
  ? T
  : T extends [...Pop<T, C>, ...infer Rest]
  ? [Pop<T, C>, ...Chunk<Rest, C>]
  : never;

Solution by JohnhanLiu #28768

type Chunk<
  T extends unknown[],
  Size extends number,
  Chunks extends unknown[] = [],
  Count extends unknown[] = [],
  Res extends unknown[] = []
> = Count["length"] extends Size
  ? Chunk<T, Size, [], [], [...Res, Chunks]>
  : T extends [infer F, ...infer R]
  ? Chunk<R, Size, [...Chunks, F], [...Count, unknown], Res>
  : Chunks["length"] extends 0
  ? Res
  : [...Res, Chunks];

Solution by DoubleWoodLin #28743

type Chunk<
  T extends readonly unknown[],
  N extends number = 1,
  Item extends unknown[] = [],
  Result extends unknown[] = []> = T extends [] ? Item extends [] ? Result : [...Result, Item] : T extends [infer Pre, ...infer Next]
    ? [...Item, Pre]['length'] extends N
        ? Chunk<Next, N, [], [...Result, [...Item, Pre]]>
        : Chunk<Next, N, [...Item, Pre], [...Result]>
    : Result

Solution by jiechliu #27701

type Chunk<
  T extends any[],
  Y extends number,
  N extends any[] = [],
  M extends any[] = []
> = T extends [infer F, ...(infer R)]
  ? N["length"] extends Y
    ? Chunk<T, Y, [], [...M, N]>
    : Chunk<R, Y, [...N, F], M>
  : N extends []
  ? M
  : [...M, N];

Solution by smileboyi #27075

type Chunk<T extends unknown[],num extends number,i extends unknown[] = [],arr extends unknown[][] = []> = T extends [] ? i extends [] ? arr : [...arr,i] : 
    T extends [infer A,...infer B] ?  
    i['length'] extends num ? Chunk<B,num,[A],[...arr,i]>:  
    Chunk<B,num,[...i,A],arr> : arr

Solution by WangZiChu199910252255 #26691

// your answers
type ChunkIter<A extends any[], L extends number, R extends any[] = []>
  = A extends [infer F, ...infer T] ?
    R['length'] extends L ? [R, ...ChunkIter<T, L, [F]>] : ChunkIter<T, L, [...R, F]>
    : [R]
type Chunk<A extends any[], L extends number> = A extends [] ? [] : ChunkIter<A, L>

Solution by adoin #26248

type Chunk<T extends unknown[], N extends number, R extends unknown[] = []> = T extends [infer First, ...infer Rest]
  ? R['length'] extends N
   ? [R, ...Chunk<Rest, N, [First]>]
   : [...Chunk<Rest, N, [...R, First]>]
  : R['length'] extends 0 ? [] : [R]

Solution by retkiewi #25914

// your answers
type FixLengthTuple<N extends number, A extends any[] = []> = 
  A['length'] extends N 
    ? A
    : FixLengthTuple<N, [...A, any]>



type Chunk<T extends any[], U extends number> = 
  T extends [...FixLengthTuple<U> , ...infer Rest] // 这样子 Rest 就空出了前面 U 个 Element
    ? T extends [...infer R, ...Rest] // R 就是前 U 个 Element 组成的 Array
      ? [R, ...Chunk<Rest, U>]
      : []
    : T extends [] 
      ? []
      : [T]

Solution by kiki-zjq #25299

type FixLengthTuple<N extends number, A extends any[] = []> = 
  A['length'] extends N 
    ? A
    : FixLengthTuple<N, [...A, any]>

type Chunk<T extends any[], U extends number> = 
  T extends [...FixLengthTuple<U> , ...infer Rest]
    ? T extends [...infer R, ...Rest]
      ? [R, ...Chunk<Rest, U>]
      : []
    : T extends [] 
      ? []
      : [T]

Solution by Minato1123 #25120

type Chunk<T extends unknown[], U extends number, Result extends unknown[] = []> = T extends [infer First, ...infer Rest]
? Result['length'] extends U
  ? [Result, ...Chunk<T, U>]
  : Chunk<Rest, U, [...Result, First]> 
: Result extends []
  ? Result
  : [Result]

Solution by NeylonR #25052

4499 - Chunk

Another lodash inspired challenge: Chunk asks us to take an array and split it into... well... chunks. It seems hard at first when you consider needing to handle remainders that aren't divisible by the chunk size, but don't worry: it all works out well in the end!

🎥 Video Explanation

Release Date: 2023-03-10 19:00 UTC

Chunk

🔢 Code

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

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

type A2 = Chunk<[1, 2, 3], 1>;
type B2 = [[1], [2], [3]];
type C2 = Expect<Equal<A2, B2>>;

type A3 = Chunk<[1, 2, 3], 2>;
type B3 = [[1, 2], [3]];
type C3 = Expect<Equal<A3, B3>>;

type A4 = Chunk<[1, 2, 3, 4], 2>;
type B4 = [[1, 2], [3, 4]];
type C4 = Expect<Equal<A4, B4>>;

type A5 = Chunk<[1, 2, 3, 4], 5>;
type B5 = [[1, 2, 3, 4]];
type C5 = Expect<Equal<A5, B5>>;

type A6 = Chunk<[1, true, 2, false], 2>;
type B6 = [[1, true], [2, false]];
type C6 = Expect<Equal<A6, B6>>;

// ============= Your Code Here =============
type Chunk<
  T extends unknown[],
  U extends number,
  Acc extends unknown[] = [],
> =
  Acc['length'] extends U
  ? [Acc, ...Chunk<T, U>] // we reached our chunk size
  : T extends [infer Head, ...infer Tail]
    ? Chunk<Tail, U, [...Acc, Head]>
    : Acc extends []
      ? Acc
      : [Acc]
;

type Chunk<
    T, 
    U extends number, 
    Temp extends unknown[] = [],
    Acc extends unknown[] = []
> =
  T extends [infer Head, ...infer Tail]
  ? Temp['length'] extends U
    ? Chunk<Tail, U, [Head], [...Acc, Temp]>
    : Chunk<Tail, U, [...Temp, Head], Acc>
  : Temp['length'] extends 0
    ? Acc
    : [...Acc, Temp]
;

type Chunk<
  T extends any[],
  U extends number = 1,
  Acc extends any[] = []
> =
  T extends [infer Head, ...infer Tail]
  ? Acc['length'] extends U
    ? [Acc, ...Chunk<T, U>]
    : Chunk<Tail, U, [...Acc, Head]>
  : Acc['length'] extends 0
    ? Acc
    : [Acc]

➕ More Solutions

For more video solutions to other challenges: see the umbrella list! https://github.com/type-challenges/type-challenges/issues/21338

Solution by dimitropoulos #24329

// your answers
type Chunk<
    T extends any[],
    N extends number,
    res extends any[] = [],
    item extends any[] = []
> = item['length'] extends N
    ? Chunk<T, N, [...res, item], []>
    : T extends [infer Left, ...infer Rest]
    ? Chunk<Rest, N, res, [...item, Left]>
    : item['length'] extends 0
    ? res
    : [...res, item]

Solution by studymachiney #24074

type Chunk<T extends any[], U extends number, _Collector extends any[] = []> =
  T extends [infer F, ...infer R] ?
  _Collector[`length`] extends U ? [_Collector, ...Chunk<T, U/*,[]*/>] : Chunk<R, U, [..._Collector, F]> :
  _Collector extends [] ? []/*空数组*/ : [_Collector];  //return&pop

// old way
// type Collector<T extends any[], U extends number, _Cluster extends any[] = []> = T extends [infer F, ...infer R] ? (U extends _Cluster["length"] ? [_Cluster, ...Collector<T, U>] : Collector<R, U, [..._Cluster, F]>) : [_Cluster];

// type Chunk<T extends any[], U extends (`${U}` extends `-${number}` | `0` ? never : number)> = T extends [] ? [] : Collector<T, U>;

Solution by E-uler #23970

type Chunk<T extends any[], U extends number, Z extends any[][] = [], O extends any[] = []> = T extends [infer F, ...infer R]
    ? [...O, F]['length'] extends U ? Chunk<R, U, [...Z, [...O, F]]> : Chunk<R, U, Z, [...O, F]>
    : O['length'] extends 0 ? Z : [...Z, O]

Solution by RBL3 #23611

type Chunk<T extends unknown[], N extends number, A extends unknown[] = [], B extends unknown[] = []> = B['length'] extends N ? Chunk<T, N, [...A, B], []> : T extends [infer L, ...infer R] ? Chunk<R, N, A, [...B, L]> : B extends [] ? A : [...A, B]

Solution by asurewall #23169