-
Notifications
You must be signed in to change notification settings - Fork 28
/
partition.ts
45 lines (42 loc) · 1.2 KB
/
partition.ts
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
type Partition = {
<T, S extends T>(list: T[], predicate: (el: T) => el is S): [
S[],
Exclude<T, S>[],
];
<T extends readonly unknown[], S>(
list: T,
predicate: (el: any) => el is S,
): Part<T, S>;
<T>(list: T[], predicate: (el: T) => unknown): [T[], T[]];
};
/**
* Takes a `list` and returns a pair of lists containing: the elements that
* match the `predicate` and those that don't, respectively.
*
* Think of it as `filter`, but the elements that don't pass the filter aren't
* discarded but returned in a separate list instead.
*
* @example
* ```
* const [strings, numbers] = partition(
* ['a', 'b', 1, 'c', 2, 3],
* (el): el is string => typeof el === 'string'
* )
* // strings: ["a", "b", "c"]
* // numbers: [1, 2, 3]
* ```
*/
const partition: Partition = <T>(list: T[], predicate: (el: T) => unknown) =>
list.reduce(
([t, f], c) => (predicate(c) ? [[...t, c], f] : [t, [...f, c]]) as any,
[[], []],
) as any;
export default partition;
type Part<T extends readonly unknown[], S> = T extends readonly [
infer F,
...infer R,
] ? [
F extends S ? [F, ...Part<R, S>[0]] : Part<R, S>[0],
F extends S ? Part<R, S>[1] : [F, ...Part<R, S>[1]],
]
: [[], []];