forked from solidjs-community/solid-primitives
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patharray.ts
More file actions
186 lines (169 loc) · 5.32 KB
/
array.ts
File metadata and controls
186 lines (169 loc) · 5.32 KB
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
import { AnyClass, compare, ItemsOf, Many, ofClass } from "../index.js";
import { withArrayCopy } from "./copy.js";
import { get } from "./object.js";
import { FlattenArray, MappingFn, Predicate } from "./types.js";
/**
* non-mutating `Array.prototype.push()`
* @returns changed array copy
*/
export const push = <T>(list: readonly T[], ...items: T[]): T[] =>
withArrayCopy(list, list => list.push(...items));
/**
* non-mutating function that drops n items from the array start.
* @returns changed array copy
*
* @example
* ```ts
* const newList = drop([1,2,3])
* newList // => [2,3]
*
* const newList = drop([1,2,3], 2)
* newList // => [3]
* ```
*/
export const drop = <T>(list: T[], n = 1): T[] => list.slice(n);
/**
* non-mutating function that drops n items from the array end.
* @returns changed array copy
*
* @example
* ```ts
* const newList = dropRight([1,2,3])
* newList // => [1,2]
*
* const newList = dropRight([1,2,3], 2)
* newList // => [1]
* ```
*/
export const dropRight = <T>(list: T[], n = 1): T[] => list.slice(0, list.length - n);
/**
* standalone `Array.prototype.filter()` that filters out passed item
* @returns changed array copy
*/
export const filterOut = <T>(list: readonly T[], item: T): T[] & { removed: number } =>
filter(list, i => i !== item);
/**
* standalone `Array.prototype.filter()`
* @returns changed array copy
*/
export function filter<T>(list: readonly T[], predicate: Predicate<T>): T[] & { removed: number } {
const newList = list.filter(predicate) as T[] & { removed: number };
newList.removed = list.length - newList.length;
return newList;
}
/**
* non-mutating `Array.prototype.sort()` as a standalone function
* @returns changed array copy
*/
export const sort = <T>(list: T[], compareFn?: (a: T, b: T) => number): T[] =>
list.slice().sort(compareFn);
/**
* standalone `Array.prototype.map()` function
*/
export const map = <T, V>(list: readonly T[], mapFn: MappingFn<T, V>): V[] => list.map(mapFn);
/**
* standalone `Array.prototype.slice()` function
*/
export const slice = <T>(list: readonly T[], start?: number, end?: number): T[] =>
list.slice(start, end);
/**
* non-mutating `Array.prototype.splice()` as a standalone function
* @returns changed array copy
*/
export const splice = <T>(
list: readonly T[],
start: number,
deleteCount: number = 0,
...items: T[]
): T[] => withArrayCopy(list, list => list.splice(start, deleteCount, ...items));
/**
* non-mutating `Array.prototype.fill()` as a standalone function
* @returns changed array copy
*/
export const fill = <T>(list: readonly T[], value: T, start?: number, end?: number): T[] =>
list.slice().fill(value, start, end);
/**
* Creates a new array concatenating array with any additional arrays and/or values.
* @param ...a values or arrays
* @returns new concatenated array
*/
export function concat<A extends any[], V extends ItemsOf<A>>(
...a: A
): Array<V extends any[] ? ItemsOf<V> : V> {
const result: any[] = [];
for (const i in a) {
Array.isArray(a[i]) ? result.push(...a[i]) : result.push(a[i]);
}
return result;
}
/**
* Remove item from array
* @returns changed array copy
*/
export const remove = <T>(list: readonly T[], item: T, ...insertItems: T[]): T[] => {
const index = list.indexOf(item);
return splice(list, index, 1, ...insertItems);
};
/**
* Remove multiple items from an array
* @returns changed array copy
*/
export const removeItems = <T>(list: readonly T[], ...items: T[]): T[] => {
const res = [];
for (let i = 0; i < list.length; i++) {
const item = list[i]!;
const ii = items.indexOf(item);
if (ii !== -1) items.splice(ii, 1);
else res.push(item);
}
return res;
};
/**
* Flattens a nested array into a one-level array
* @returns changed array copy
*/
export const flatten = <T extends any[]>(arr: T): FlattenArray<T>[] =>
arr.reduce((flat, next) => flat.concat(Array.isArray(next) ? (flatten as any)(next) : next), []);
/**
* Sort an array by object key, or multiple keys
* @returns changed array copy
*/
export const sortBy = <T>(
arr: T[],
...paths: T extends object ? (Many<keyof T> | Many<(item: T) => any>)[] : Many<(item: T) => any>[]
): T[] =>
flatten(paths).reduce(
(source, path) =>
sort(source, (a, b) =>
typeof path === "function"
? compare(path(a), path(b))
: compare(get(a as any, path), get(b as any, path)),
),
arr,
);
/**
* Returns a subset of items that are instances of provided Classes
* @param list list of original items
* @param ...classes list or classes
* @returns changed array copy
*/
export const filterInstance = <T, I extends AnyClass[]>(
list: readonly T[],
...classes: I
): Extract<T, InstanceType<ItemsOf<I>>>[] =>
(classes.length === 1
? list.filter(item => ofClass(item, classes[0]!))
: list.filter(item => item && classes.some(c => ofClass(item, c)))) as any[];
/**
* Returns a subset of items that aren't instances of provided Classes
* @param list list of original items
* @param ...classes list or classes
* @returns changed array copy
*/
export const filterOutInstance = <T, I extends AnyClass[]>(
list: readonly T[],
...classes: I
): Exclude<T, InstanceType<ItemsOf<I>>>[] =>
(classes.length === 1
? list.filter(item => item && !ofClass(item, classes[0]!))
: list.filter(item => item && !classes.some(c => ofClass(item, c)))) as any[];