@stacksjs/arrays 0.74.32 → 0.74.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/arr.d.ts +1 -0
- package/dist/arr.js +1 -1
- package/dist/transform.d.ts +383 -0
- package/dist/transform.js +1 -0
- package/package.json +1 -1
package/dist/arr.d.ts
CHANGED
package/dist/arr.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./contains";export*from"./helpers";export*from"./math";
|
|
1
|
+
export*from"./contains";export*from"./helpers";export*from"./math";export*from"./transform";
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shaping an array: slicing it, grouping it, pairing it with another.
|
|
3
|
+
*
|
|
4
|
+
* `helpers.ts` holds the conversions and mutations, `math.ts` the statistics,
|
|
5
|
+
* `contains.ts` the membership questions. These are the operations that were
|
|
6
|
+
* reached for often enough that applications kept writing them inline, and
|
|
7
|
+
* that a request to add Remeda (stacksjs/stacks#412) was really asking for -
|
|
8
|
+
* answered by implementing them here rather than by taking a second utility
|
|
9
|
+
* library and a second idiom for operations the framework already half had.
|
|
10
|
+
*
|
|
11
|
+
* Every function takes the array first and returns a new one. Nothing mutates
|
|
12
|
+
* its input, and nothing throws on an empty array: an empty input produces an
|
|
13
|
+
* empty output, or `undefined` where a single element was asked for.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Split an array into consecutive groups of at most `size`.
|
|
17
|
+
*
|
|
18
|
+
* The last group is short when the length does not divide evenly, which is the
|
|
19
|
+
* behaviour that makes this useful for batching - a caller that wants only
|
|
20
|
+
* whole groups can drop it.
|
|
21
|
+
*
|
|
22
|
+
* @category Array
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* chunk([1, 2, 3, 4, 5], 2) // [[1, 2], [3, 4], [5]]
|
|
26
|
+
* chunk([], 3) // []
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function chunk<T>(array: readonly T[], size: number): T[][];
|
|
30
|
+
/**
|
|
31
|
+
* Drop `null` and `undefined`, and say so in the type.
|
|
32
|
+
*
|
|
33
|
+
* Deliberately not "drop every falsy value", which is the other common reading:
|
|
34
|
+
* that one silently removes `0`, `''` and `false`, which are ordinary data far
|
|
35
|
+
* more often than they are mistakes, and it is `array.filter(Boolean)` when it
|
|
36
|
+
* really is wanted. Narrowing to `NonNullable<T>` is the part a hand-written
|
|
37
|
+
* filter does not give you.
|
|
38
|
+
*
|
|
39
|
+
* @category Array
|
|
40
|
+
* @example
|
|
41
|
+
* ```ts
|
|
42
|
+
* compact([1, null, 2, undefined, 3]) // [1, 2, 3]
|
|
43
|
+
* compact([0, '', false, null]) // [0, '', false]
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function compact<T>(array: readonly T[]): NonNullable<T>[];
|
|
47
|
+
/**
|
|
48
|
+
* The first element, or `undefined` when there is none.
|
|
49
|
+
*
|
|
50
|
+
* The counterpart to the existing `last`. `array[0]` is the same thing until
|
|
51
|
+
* `noUncheckedIndexedAccess` is on, at which point this is the version whose
|
|
52
|
+
* type admits that an empty array has no first element.
|
|
53
|
+
*
|
|
54
|
+
* @category Array
|
|
55
|
+
* @example
|
|
56
|
+
* ```ts
|
|
57
|
+
* first([1, 2, 3]) // 1
|
|
58
|
+
* first([]) // undefined
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function first<T>(array: readonly T[]): T | undefined;
|
|
62
|
+
/**
|
|
63
|
+
* Everything after the first element.
|
|
64
|
+
*
|
|
65
|
+
* @category Array
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* tail([1, 2, 3]) // [2, 3]
|
|
69
|
+
* tail([1]) // []
|
|
70
|
+
* tail([]) // []
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function tail<T>(array: readonly T[]): T[];
|
|
74
|
+
/**
|
|
75
|
+
* The first `count` elements.
|
|
76
|
+
*
|
|
77
|
+
* A negative or zero `count` takes nothing, rather than counting from the end -
|
|
78
|
+
* `slice`'s negative-index behaviour is a trap here, because `take(xs, -2)`
|
|
79
|
+
* reads as "take two" and would silently return everything but the last two.
|
|
80
|
+
*
|
|
81
|
+
* @category Array
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* take([1, 2, 3, 4], 2) // [1, 2]
|
|
85
|
+
* take([1, 2, 3, 4], 10) // [1, 2, 3, 4]
|
|
86
|
+
* take([1, 2, 3, 4], -2) // []
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
export declare function take<T>(array: readonly T[], count: number): T[];
|
|
90
|
+
/**
|
|
91
|
+
* The last `count` elements, in their original order.
|
|
92
|
+
*
|
|
93
|
+
* @category Array
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* takeLast([1, 2, 3, 4], 2) // [3, 4]
|
|
97
|
+
* takeLast([1, 2], 0) // []
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
export declare function takeLast<T>(array: readonly T[], count: number): T[];
|
|
101
|
+
/**
|
|
102
|
+
* Elements from the start, stopping at the first that fails `predicate`.
|
|
103
|
+
*
|
|
104
|
+
* Stops rather than filters: a later element that would pass is not included,
|
|
105
|
+
* which is the difference between this and `filter` and the whole reason to
|
|
106
|
+
* reach for it.
|
|
107
|
+
*
|
|
108
|
+
* @category Array
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* takeWhile([1, 2, 5, 1], n => n < 3) // [1, 2]
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare function takeWhile<T>(array: readonly T[], predicate: (value: T, index: number) => boolean): T[];
|
|
115
|
+
/**
|
|
116
|
+
* Elements from the end, stopping at the last that fails `predicate`, returned
|
|
117
|
+
* in their original order.
|
|
118
|
+
*
|
|
119
|
+
* @category Array
|
|
120
|
+
* @example
|
|
121
|
+
* ```ts
|
|
122
|
+
* takeLastWhile([1, 5, 2, 1], n => n < 3) // [2, 1]
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export declare function takeLastWhile<T>(array: readonly T[], predicate: (value: T, index: number) => boolean): T[];
|
|
126
|
+
/**
|
|
127
|
+
* Everything after the first `count` elements.
|
|
128
|
+
*
|
|
129
|
+
* @category Array
|
|
130
|
+
* @example
|
|
131
|
+
* ```ts
|
|
132
|
+
* drop([1, 2, 3, 4], 2) // [3, 4]
|
|
133
|
+
* drop([1, 2, 3, 4], -1) // [1, 2, 3, 4]
|
|
134
|
+
* ```
|
|
135
|
+
*/
|
|
136
|
+
export declare function drop<T>(array: readonly T[], count: number): T[];
|
|
137
|
+
/**
|
|
138
|
+
* Everything except the last `count` elements.
|
|
139
|
+
*
|
|
140
|
+
* @category Array
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* dropLast([1, 2, 3, 4], 2) // [1, 2]
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export declare function dropLast<T>(array: readonly T[], count: number): T[];
|
|
147
|
+
/**
|
|
148
|
+
* Everything from the first element that fails `predicate` onwards.
|
|
149
|
+
*
|
|
150
|
+
* @category Array
|
|
151
|
+
* @example
|
|
152
|
+
* ```ts
|
|
153
|
+
* dropWhile([1, 2, 5, 1], n => n < 3) // [5, 1]
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare function dropWhile<T>(array: readonly T[], predicate: (value: T, index: number) => boolean): T[];
|
|
157
|
+
/**
|
|
158
|
+
* Everything up to the last element that fails `predicate`.
|
|
159
|
+
*
|
|
160
|
+
* @category Array
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* dropLastWhile([1, 5, 2, 1], n => n < 3) // [1, 5]
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export declare function dropLastWhile<T>(array: readonly T[], predicate: (value: T, index: number) => boolean): T[];
|
|
167
|
+
/**
|
|
168
|
+
* Group elements under the key each one produces.
|
|
169
|
+
*
|
|
170
|
+
* Insertion order is preserved within every group, and a key of `undefined`
|
|
171
|
+
* drops the element rather than creating an `"undefined"` bucket - which is
|
|
172
|
+
* what lets this double as a filter-and-group in one pass.
|
|
173
|
+
*
|
|
174
|
+
* @category Array
|
|
175
|
+
* @example
|
|
176
|
+
* ```ts
|
|
177
|
+
* groupBy([1, 2, 3, 4], n => n % 2 ? 'odd' : 'even')
|
|
178
|
+
* // { odd: [1, 3], even: [2, 4] }
|
|
179
|
+
* ```
|
|
180
|
+
*/
|
|
181
|
+
export declare function groupBy<T, K extends PropertyKey>(array: readonly T[], key: (value: T, index: number) => K | undefined): Partial<Record<K, T[]>>;
|
|
182
|
+
/**
|
|
183
|
+
* Index elements by the key each one produces, last one winning.
|
|
184
|
+
*
|
|
185
|
+
* Last-wins rather than first-wins because this is normally used to build a
|
|
186
|
+
* lookup from a list that is already in priority order, and because it matches
|
|
187
|
+
* what an assignment loop would do.
|
|
188
|
+
*
|
|
189
|
+
* @category Array
|
|
190
|
+
* @example
|
|
191
|
+
* ```ts
|
|
192
|
+
* keyBy([{ id: 'a', n: 1 }, { id: 'b', n: 2 }], user => user.id)
|
|
193
|
+
* // { a: { id: 'a', n: 1 }, b: { id: 'b', n: 2 } }
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
export declare function keyBy<T, K extends PropertyKey>(array: readonly T[], key: (value: T, index: number) => K | undefined): Partial<Record<K, T>>;
|
|
197
|
+
/**
|
|
198
|
+
* How many elements produce each key.
|
|
199
|
+
*
|
|
200
|
+
* @category Array
|
|
201
|
+
* @example
|
|
202
|
+
* ```ts
|
|
203
|
+
* countBy(['a', 'bb', 'c'], word => word.length) // { 1: 2, 2: 1 }
|
|
204
|
+
* ```
|
|
205
|
+
*/
|
|
206
|
+
export declare function countBy<T, K extends PropertyKey>(array: readonly T[], key: (value: T, index: number) => K | undefined): Partial<Record<K, number>>;
|
|
207
|
+
/**
|
|
208
|
+
* Sort by one or more selectors, without mutating the input.
|
|
209
|
+
*
|
|
210
|
+
* `Array.prototype.sort` sorts in place and compares stringified values, so
|
|
211
|
+
* `[10, 9].sort()` is `[10, 9]`. This copies first and compares the selected
|
|
212
|
+
* values by their own type, falling through to the next selector on a tie -
|
|
213
|
+
* which is what makes "by role, then by name" a single call.
|
|
214
|
+
*
|
|
215
|
+
* @category Array
|
|
216
|
+
* @example
|
|
217
|
+
* ```ts
|
|
218
|
+
* sortBy(users, user => user.age)
|
|
219
|
+
* sortBy(users, { by: user => user.age, order: 'desc' }, user => user.name)
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export declare function sortBy<T>(array: readonly T[], ...selectors: SortSelector<T>[]): T[];
|
|
223
|
+
/**
|
|
224
|
+
* Sum the number each element produces.
|
|
225
|
+
*
|
|
226
|
+
* `0` for an empty array, which is the identity for addition and lets a caller
|
|
227
|
+
* total a filtered list without checking whether anything survived.
|
|
228
|
+
*
|
|
229
|
+
* @category Array
|
|
230
|
+
* @example
|
|
231
|
+
* ```ts
|
|
232
|
+
* sumBy(orders, order => order.total) // 41.5
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
export declare function sumBy<T>(array: readonly T[], value: (item: T, index: number) => number): number;
|
|
236
|
+
/**
|
|
237
|
+
* The mean of the number each element produces, or `undefined` when empty.
|
|
238
|
+
*
|
|
239
|
+
* `undefined` rather than `NaN` or a throw: an empty list has no mean, and a
|
|
240
|
+
* caller that has to handle that is better served by a type that says so than
|
|
241
|
+
* by a number that poisons every later arithmetic.
|
|
242
|
+
*
|
|
243
|
+
* @category Array
|
|
244
|
+
* @example
|
|
245
|
+
* ```ts
|
|
246
|
+
* meanBy(orders, order => order.total) // 20.75
|
|
247
|
+
* meanBy([], order => order.total) // undefined
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export declare function meanBy<T>(array: readonly T[], value: (item: T, index: number) => number): number | undefined;
|
|
251
|
+
/**
|
|
252
|
+
* The element with the largest selected value, or `undefined` when empty.
|
|
253
|
+
*
|
|
254
|
+
* Returns the *element*, not the value - which is the difference from `max`
|
|
255
|
+
* and the reason to reach for it. Ties go to the first, so the result is stable
|
|
256
|
+
* for an already-ordered input.
|
|
257
|
+
*
|
|
258
|
+
* @category Array
|
|
259
|
+
* @example
|
|
260
|
+
* ```ts
|
|
261
|
+
* maxBy(users, user => user.age) // the oldest user
|
|
262
|
+
* ```
|
|
263
|
+
*/
|
|
264
|
+
export declare function maxBy<T>(array: readonly T[], value: (item: T, index: number) => number): T | undefined;
|
|
265
|
+
/**
|
|
266
|
+
* The element with the smallest selected value, or `undefined` when empty.
|
|
267
|
+
*
|
|
268
|
+
* @category Array
|
|
269
|
+
* @example
|
|
270
|
+
* ```ts
|
|
271
|
+
* minBy(users, user => user.age) // the youngest user
|
|
272
|
+
* ```
|
|
273
|
+
*/
|
|
274
|
+
export declare function minBy<T>(array: readonly T[], value: (item: T, index: number) => number): T | undefined;
|
|
275
|
+
/**
|
|
276
|
+
* Pair up two arrays, stopping at the shorter one.
|
|
277
|
+
*
|
|
278
|
+
* @category Array
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* zip([1, 2, 3], ['a', 'b']) // [[1, 'a'], [2, 'b']]
|
|
282
|
+
* ```
|
|
283
|
+
*/
|
|
284
|
+
export declare function zip<A, B>(first: readonly A[], second: readonly B[]): Array<[A, B]>;
|
|
285
|
+
/**
|
|
286
|
+
* Combine two arrays element-wise, stopping at the shorter one.
|
|
287
|
+
*
|
|
288
|
+
* @category Array
|
|
289
|
+
* @example
|
|
290
|
+
* ```ts
|
|
291
|
+
* zipWith([1, 2], [10, 20], (a, b) => a + b) // [11, 22]
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
export declare function zipWith<A, B, R>(first: readonly A[], second: readonly B[], combine: (a: A, b: B, index: number) => R): R[];
|
|
295
|
+
/**
|
|
296
|
+
* The inverse of {@link zip}: pairs back into two arrays.
|
|
297
|
+
*
|
|
298
|
+
* @category Array
|
|
299
|
+
* @example
|
|
300
|
+
* ```ts
|
|
301
|
+
* unzip([[1, 'a'], [2, 'b']]) // [[1, 2], ['a', 'b']]
|
|
302
|
+
* ```
|
|
303
|
+
*/
|
|
304
|
+
export declare function unzip<A, B>(pairs: ReadonlyArray<readonly [A, B]>): [A[], B[]];
|
|
305
|
+
/**
|
|
306
|
+
* Elements of `array` that are not in `other`, keeping duplicates.
|
|
307
|
+
*
|
|
308
|
+
* Membership is `Set` identity - `SameValueZero`, so `NaN` matches `NaN` and
|
|
309
|
+
* `0` matches `-0`, and two structurally equal objects do not match. A caller
|
|
310
|
+
* comparing objects wants a selector, not this.
|
|
311
|
+
*
|
|
312
|
+
* @category Array
|
|
313
|
+
* @example
|
|
314
|
+
* ```ts
|
|
315
|
+
* difference([1, 2, 2, 3], [2]) // [1, 3]
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
export declare function difference<T>(array: readonly T[], other: readonly T[]): T[];
|
|
319
|
+
/**
|
|
320
|
+
* Elements present in both, in the order of the first, without duplicates.
|
|
321
|
+
*
|
|
322
|
+
* @category Array
|
|
323
|
+
* @example
|
|
324
|
+
* ```ts
|
|
325
|
+
* intersection([1, 2, 2, 3], [2, 3, 4]) // [2, 3]
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export declare function intersection<T>(array: readonly T[], other: readonly T[]): T[];
|
|
329
|
+
/**
|
|
330
|
+
* Every element across the given arrays, in first-seen order, without
|
|
331
|
+
* duplicates.
|
|
332
|
+
*
|
|
333
|
+
* @category Array
|
|
334
|
+
* @example
|
|
335
|
+
* ```ts
|
|
336
|
+
* union([1, 2], [2, 3], [3, 4]) // [1, 2, 3, 4]
|
|
337
|
+
* ```
|
|
338
|
+
*/
|
|
339
|
+
export declare function union<T>(...arrays: ReadonlyArray<readonly T[]>): T[];
|
|
340
|
+
/**
|
|
341
|
+
* Cut an array in two at `index`.
|
|
342
|
+
*
|
|
343
|
+
* A negative index counts from the end, matching `slice`; out of range in
|
|
344
|
+
* either direction gives one empty half rather than throwing.
|
|
345
|
+
*
|
|
346
|
+
* @category Array
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* splitAt([1, 2, 3, 4], 2) // [[1, 2], [3, 4]]
|
|
350
|
+
* splitAt([1, 2, 3, 4], -1) // [[1, 2, 3], [4]]
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
353
|
+
export declare function splitAt<T>(array: readonly T[], index: number): [T[], T[]];
|
|
354
|
+
/**
|
|
355
|
+
* Cut an array in two at the first element that satisfies `predicate`, which
|
|
356
|
+
* begins the second half.
|
|
357
|
+
*
|
|
358
|
+
* When nothing satisfies it, everything lands in the first half - so the two
|
|
359
|
+
* halves always concatenate back to the input.
|
|
360
|
+
*
|
|
361
|
+
* @category Array
|
|
362
|
+
* @example
|
|
363
|
+
* ```ts
|
|
364
|
+
* splitWhen([1, 2, 3, 1], n => n > 2) // [[1, 2], [3, 1]]
|
|
365
|
+
* splitWhen([1, 2], n => n > 9) // [[1, 2], []]
|
|
366
|
+
* ```
|
|
367
|
+
*/
|
|
368
|
+
export declare function splitWhen<T>(array: readonly T[], predicate: (value: T, index: number) => boolean): [T[], T[]];
|
|
369
|
+
/**
|
|
370
|
+
* Build an array by calling `create` with each index.
|
|
371
|
+
*
|
|
372
|
+
* @category Array
|
|
373
|
+
* @example
|
|
374
|
+
* ```ts
|
|
375
|
+
* times(3, index => index * 2) // [0, 2, 4]
|
|
376
|
+
* ```
|
|
377
|
+
*/
|
|
378
|
+
export declare function times<T>(count: number, create: (index: number) => T): T[];
|
|
379
|
+
/** How one `sortBy` selector orders: the value to compare, and the direction. */
|
|
380
|
+
export type SortSelector<T> = ((value: T) => number | string | bigint | boolean | Date) | {
|
|
381
|
+
by: (value: T) => number | string | bigint | boolean | Date
|
|
382
|
+
order?: 'asc' | 'desc'
|
|
383
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function chunk(array,size){if(!Number.isInteger(size)||size<1)throw TypeError(`chunk: size must be a positive integer, got ${size}`);const chunks=[];for(let index=0;index<array.length;index+=size)chunks.push(array.slice(index,index+size));return chunks}export function compact(array){return array.filter((value)=>value!==null&&value!==void 0)}export function first(array){return array[0]}export function tail(array){return array.slice(1)}export function take(array,count){return count<=0?[]:array.slice(0,count)}export function takeLast(array,count){return count<=0?[]:array.slice(Math.max(0,array.length-count))}export function takeWhile(array,predicate){const result=[];for(const[index,value]of array.entries()){if(!predicate(value,index))break;result.push(value)}return result}export function takeLastWhile(array,predicate){for(let index=array.length-1;index>=0;index--)if(!predicate(array[index],index))return array.slice(index+1);return array.slice()}export function drop(array,count){return count<=0?array.slice():array.slice(count)}export function dropLast(array,count){return count<=0?array.slice():array.slice(0,Math.max(0,array.length-count))}export function dropWhile(array,predicate){for(const[index,value]of array.entries())if(!predicate(value,index))return array.slice(index);return[]}export function dropLastWhile(array,predicate){for(let index=array.length-1;index>=0;index--)if(!predicate(array[index],index))return array.slice(0,index+1);return[]}export function groupBy(array,key){const groups={};for(const[index,value]of array.entries()){const group=key(value,index);if(group===void 0)continue;(groups[group]??=[]).push(value)}return groups}export function keyBy(array,key){const indexed={};for(const[index,value]of array.entries()){const at=key(value,index);if(at!==void 0)indexed[at]=value}return indexed}export function countBy(array,key){const counts={};for(const[index,value]of array.entries()){const at=key(value,index);if(at!==void 0)counts[at]=(counts[at]??0)+1}return counts}function compareSelected(a,b){if(a instanceof Date&&b instanceof Date)return a.getTime()-b.getTime();if(typeof a==="string"&&typeof b==="string")return a<b?-1:a>b?1:0;if(typeof a==="boolean"&&typeof b==="boolean")return Number(a)-Number(b);if(typeof a==="bigint"&&typeof b==="bigint")return a<b?-1:a>b?1:0;return Number(a)-Number(b)}export function sortBy(array,...selectors){const normalized=selectors.map((selector)=>typeof selector==="function"?{by:selector,order:"asc"}:{order:"asc",...selector});return array.slice().sort((left,right)=>{for(const{by,order}of normalized){const comparison=compareSelected(by(left),by(right));if(comparison!==0)return order==="desc"?-comparison:comparison}return 0})}export function sumBy(array,value){let total=0;for(const[index,item]of array.entries())total+=value(item,index);return total}export function meanBy(array,value){return array.length===0?void 0:sumBy(array,value)/array.length}export function maxBy(array,value){let best,bestValue=Number.NEGATIVE_INFINITY;for(const[index,item]of array.entries()){const candidate=value(item,index);if(candidate>bestValue){bestValue=candidate;best=item}}return best}export function minBy(array,value){let best,bestValue=Number.POSITIVE_INFINITY;for(const[index,item]of array.entries()){const candidate=value(item,index);if(candidate<bestValue){bestValue=candidate;best=item}}return best}export function zip(first,second){const length=Math.min(first.length,second.length),pairs=[];for(let index=0;index<length;index++)pairs.push([first[index],second[index]]);return pairs}export function zipWith(first,second,combine){const length=Math.min(first.length,second.length),combined=[];for(let index=0;index<length;index++)combined.push(combine(first[index],second[index],index));return combined}export function unzip(pairs){const first=[],second=[];for(const[a,b]of pairs){first.push(a);second.push(b)}return[first,second]}export function difference(array,other){const exclude=new Set(other);return array.filter((value)=>!exclude.has(value))}export function intersection(array,other){const include=new Set(other),seen=new Set;return array.filter((value)=>{if(!include.has(value)||seen.has(value))return!1;seen.add(value);return!0})}export function union(...arrays){return[...new Set(arrays.flat())]}export function splitAt(array,index){return[array.slice(0,index),array.slice(index)]}export function splitWhen(array,predicate){for(const[index,value]of array.entries())if(predicate(value,index))return[array.slice(0,index),array.slice(index)];return[array.slice(),[]]}export function times(count,create){if(!Number.isInteger(count)||count<0)throw TypeError(`times: count must be a non-negative integer, got ${count}`);const result=Array.from({length:count});for(let index=0;index<count;index++)result[index]=create(index);return result}
|