ts-data-forge 1.5.1 → 2.0.0
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/README.md +13 -1
- package/dist/array/array-utils.d.mts +693 -351
- package/dist/array/array-utils.d.mts.map +1 -1
- package/dist/array/array-utils.mjs +474 -1541
- package/dist/array/array-utils.mjs.map +1 -1
- package/dist/array/index.d.mts +0 -1
- package/dist/array/index.d.mts.map +1 -1
- package/dist/array/index.mjs +0 -1
- package/dist/array/index.mjs.map +1 -1
- package/dist/collections/imap-mapped.mjs.map +1 -1
- package/dist/collections/imap.mjs.map +1 -1
- package/dist/collections/iset-mapped.mjs.map +1 -1
- package/dist/collections/iset.mjs.map +1 -1
- package/dist/collections/queue.mjs +0 -1
- package/dist/collections/queue.mjs.map +1 -1
- package/dist/collections/stack.mjs +4 -5
- package/dist/collections/stack.mjs.map +1 -1
- package/dist/functional/match.d.mts +2 -33
- package/dist/functional/match.d.mts.map +1 -1
- package/dist/functional/match.mjs +2 -119
- package/dist/functional/match.mjs.map +1 -1
- package/dist/functional/optional.d.mts +29 -51
- package/dist/functional/optional.d.mts.map +1 -1
- package/dist/functional/optional.mjs +40 -171
- package/dist/functional/optional.mjs.map +1 -1
- package/dist/functional/pipe.d.mts +2 -15
- package/dist/functional/pipe.d.mts.map +1 -1
- package/dist/functional/pipe.mjs +2 -110
- package/dist/functional/pipe.mjs.map +1 -1
- package/dist/functional/result.d.mts +18 -45
- package/dist/functional/result.d.mts.map +1 -1
- package/dist/functional/result.mjs +40 -196
- package/dist/functional/result.mjs.map +1 -1
- package/dist/globals.d.mts +10 -9
- package/dist/index.mjs +0 -1
- package/dist/index.mjs.map +1 -1
- package/dist/iterator/range.d.mts +2 -6
- package/dist/iterator/range.d.mts.map +1 -1
- package/dist/iterator/range.mjs +2 -93
- package/dist/iterator/range.mjs.map +1 -1
- package/dist/json/json.mjs +0 -1
- package/dist/json/json.mjs.map +1 -1
- package/dist/number/num.d.mts +3 -6
- package/dist/number/num.d.mts.map +1 -1
- package/dist/number/num.mjs +4 -22
- package/dist/number/num.mjs.map +1 -1
- package/dist/number/refined-number-utils.mjs.map +1 -1
- package/dist/object/object.d.mts +4 -10
- package/dist/object/object.d.mts.map +1 -1
- package/dist/object/object.mjs +8 -140
- package/dist/object/object.mjs.map +1 -1
- package/dist/others/map-nullable.d.mts +2 -6
- package/dist/others/map-nullable.d.mts.map +1 -1
- package/dist/others/map-nullable.mjs +2 -146
- package/dist/others/map-nullable.mjs.map +1 -1
- package/dist/others/memoize-function.mjs.map +1 -1
- package/dist/others/unknown-to-string.mjs.map +1 -1
- package/package.json +12 -12
- package/src/array/array-utils-modification.test.mts +93 -67
- package/src/array/array-utils-overload-type-error.test.mts +2 -2
- package/src/array/array-utils-reducing-value.test.mts +31 -37
- package/src/array/array-utils-slice-clamped.test.mts +94 -70
- package/src/array/array-utils-transformation.test.mts +557 -10
- package/src/array/array-utils.mts +1835 -1000
- package/src/array/index.mts +0 -1
- package/src/collections/queue.mts +2 -2
- package/src/collections/stack.mts +8 -8
- package/src/functional/match.mts +18 -44
- package/src/functional/optional.mts +88 -102
- package/src/functional/pipe.mts +25 -20
- package/src/functional/result.mts +114 -124
- package/src/globals.d.mts +10 -9
- package/src/iterator/range.mts +14 -17
- package/src/number/num.mts +16 -12
- package/src/object/object.mts +30 -45
- package/src/others/map-nullable.mts +13 -15
- package/dist/array/tuple-utils.d.mts +0 -421
- package/dist/array/tuple-utils.d.mts.map +0 -1
- package/dist/array/tuple-utils.mjs +0 -391
- package/dist/array/tuple-utils.mjs.map +0 -1
- package/src/array/tuple-utils.mts +0 -519
- package/src/array/tuple-utils.test.mts +0 -518
|
@@ -2,7 +2,6 @@ import '../collections/imap-mapped.mjs';
|
|
|
2
2
|
import { IMap } from '../collections/imap.mjs';
|
|
3
3
|
import '../collections/iset-mapped.mjs';
|
|
4
4
|
import '../collections/iset.mjs';
|
|
5
|
-
import './tuple-utils.mjs';
|
|
6
5
|
import { isString, isUndefined } from '../guard/is-type.mjs';
|
|
7
6
|
import { Optional } from '../functional/optional.mjs';
|
|
8
7
|
import { pipe } from '../functional/pipe.mjs';
|
|
@@ -32,7 +31,7 @@ import '../number/branded-types/safe-int.mjs';
|
|
|
32
31
|
import '../number/branded-types/safe-uint.mjs';
|
|
33
32
|
import '../number/branded-types/uint.mjs';
|
|
34
33
|
import '../number/branded-types/uint16.mjs';
|
|
35
|
-
import {
|
|
34
|
+
import { Uint32, asUint32 } from '../number/branded-types/uint32.mjs';
|
|
36
35
|
import '../number/enum/int8.mjs';
|
|
37
36
|
import '../number/enum/uint8.mjs';
|
|
38
37
|
import { Num } from '../number/num.mjs';
|
|
@@ -77,7 +76,7 @@ var Arr;
|
|
|
77
76
|
* // Type: IntersectBrand<PositiveNumber, SizeType.Arr>
|
|
78
77
|
* // Value: 3 (branded, guaranteed positive)
|
|
79
78
|
*
|
|
80
|
-
* const nonEmpty: NonEmptyArray<string> = ['a', 'b']
|
|
79
|
+
* const nonEmpty: NonEmptyArray<string> = ['a', 'b'];
|
|
81
80
|
* const nonEmptySize = Arr.size(nonEmpty);
|
|
82
81
|
* // Type: IntersectBrand<PositiveNumber, SizeType.Arr>
|
|
83
82
|
* // Guaranteed to be > 0
|
|
@@ -107,13 +106,6 @@ var Arr;
|
|
|
107
106
|
* const indices = Arr.seq(dataSize); // Creates [0, 1, 2]
|
|
108
107
|
* const zeros = Arr.zeros(dataSize); // Creates [0, 0, 0]
|
|
109
108
|
*
|
|
110
|
-
* // Safe for bounds checking
|
|
111
|
-
* const isValidIndex = (index: number) => index >= 0 && index < dataSize;
|
|
112
|
-
*
|
|
113
|
-
* // Comparison with other sizes
|
|
114
|
-
* const otherArray = ['a', 'b'];
|
|
115
|
-
* const sizeDiff = Uint32.sub(Arr.size(data), Arr.size(otherArray)); // 1
|
|
116
|
-
*
|
|
117
109
|
* // Functional composition
|
|
118
110
|
* const arrays = [
|
|
119
111
|
* [1, 2],
|
|
@@ -140,9 +132,9 @@ var Arr;
|
|
|
140
132
|
* @see {@link isEmpty} for checking if size is 0
|
|
141
133
|
* @see {@link isNonEmpty} for checking if size > 0
|
|
142
134
|
*/
|
|
135
|
+
Arr.size = (array) =>
|
|
143
136
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
144
|
-
|
|
145
|
-
Arr.length = Arr.size;
|
|
137
|
+
array.length;
|
|
146
138
|
// type guard
|
|
147
139
|
/**
|
|
148
140
|
* Type guard that checks if a value is an array, excluding types that cannot be arrays.
|
|
@@ -192,26 +184,11 @@ var Arr;
|
|
|
192
184
|
* if (Arr.isEmpty(arr)) {
|
|
193
185
|
* // arr is now typed as readonly []
|
|
194
186
|
* console.log('Array is empty');
|
|
187
|
+
* // arr[0]; // type error!
|
|
195
188
|
* return 0;
|
|
196
|
-
* } else {
|
|
197
|
-
* // arr is now typed as NonEmptyArray<number>
|
|
198
|
-
* return arr[0]; // Safe access - TypeScript knows it's non-empty
|
|
199
189
|
* }
|
|
200
190
|
* }
|
|
201
191
|
*
|
|
202
|
-
* // Conditional processing
|
|
203
|
-
* const data = [10, 20, 30];
|
|
204
|
-
* if (!Arr.isEmpty(data)) {
|
|
205
|
-
* // Safe to access elements
|
|
206
|
-
* const firstElement = data[0]; // No undefined risk
|
|
207
|
-
* const lastElement = data[data.length - 1];
|
|
208
|
-
* }
|
|
209
|
-
*
|
|
210
|
-
* // Filtering empty arrays
|
|
211
|
-
* const arrayList: readonly number[][] = [[1, 2], [], [3], []];
|
|
212
|
-
* const nonEmptyArrays = arrayList.filter(arr => !Arr.isEmpty(arr));
|
|
213
|
-
* // nonEmptyArrays: [[1, 2], [3]]
|
|
214
|
-
*
|
|
215
192
|
* // Early returns
|
|
216
193
|
* function sumArray(numbers: readonly number[]): number {
|
|
217
194
|
* if (Arr.isEmpty(numbers)) {
|
|
@@ -220,12 +197,6 @@ var Arr;
|
|
|
220
197
|
* return numbers.reduce((sum, n) => sum + n, 0);
|
|
221
198
|
* }
|
|
222
199
|
*
|
|
223
|
-
* // Type inference examples
|
|
224
|
-
* const testEmpty = [] as const;
|
|
225
|
-
* const testNonEmpty = [1, 2] as const;
|
|
226
|
-
*
|
|
227
|
-
* expectType<Parameters<typeof Arr.isEmpty>[0], readonly unknown[]>('=');
|
|
228
|
-
* expectType<ReturnType<typeof Arr.isEmpty>, boolean>('=');
|
|
229
200
|
* ```
|
|
230
201
|
*
|
|
231
202
|
* @see {@link isNonEmpty} for the opposite check (non-empty arrays)
|
|
@@ -266,16 +237,14 @@ var Arr;
|
|
|
266
237
|
*
|
|
267
238
|
* // Safe operations on non-empty arrays
|
|
268
239
|
* function processData(data: readonly string[]) {
|
|
269
|
-
* if (Arr.isNonEmpty(data))
|
|
270
|
-
*
|
|
271
|
-
*
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
*
|
|
275
|
-
*
|
|
276
|
-
*
|
|
277
|
-
* const reduced = data.reduce((acc, item) => acc + item.length, 0);
|
|
278
|
-
* }
|
|
240
|
+
* if (!Arr.isNonEmpty(data)) return; // early return pattern
|
|
241
|
+
*
|
|
242
|
+
* // This is now safe without undefined checks
|
|
243
|
+
* const first = data[0];
|
|
244
|
+
*
|
|
245
|
+
* // Can safely use non-empty array methods
|
|
246
|
+
* const lastElement = Arr.last(data);
|
|
247
|
+
*
|
|
279
248
|
* }
|
|
280
249
|
*
|
|
281
250
|
* // Filtering and working with arrays
|
|
@@ -300,7 +269,7 @@ var Arr;
|
|
|
300
269
|
* }
|
|
301
270
|
*
|
|
302
271
|
* // numbers is now NonEmptyArray<number>
|
|
303
|
-
* return
|
|
272
|
+
* return Arr.sum(numbers) / Arr.size(numbers);
|
|
304
273
|
* }
|
|
305
274
|
*
|
|
306
275
|
* // Functional composition
|
|
@@ -432,8 +401,9 @@ var Arr;
|
|
|
432
401
|
* expectType<typeof maybeEmpty, readonly 0[]>('=');
|
|
433
402
|
* ```
|
|
434
403
|
*/
|
|
404
|
+
Arr.zeros = (len) =>
|
|
435
405
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
436
|
-
|
|
406
|
+
Array.from({ length: len }).fill(0);
|
|
437
407
|
/**
|
|
438
408
|
* Creates a sequence of consecutive integers from 0 to `len-1`.
|
|
439
409
|
*
|
|
@@ -475,8 +445,9 @@ var Arr;
|
|
|
475
445
|
* expectType<typeof single, readonly [0]>('=');
|
|
476
446
|
* ```
|
|
477
447
|
*/
|
|
448
|
+
Arr.seq = (len) =>
|
|
478
449
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
479
|
-
|
|
450
|
+
Array.from({ length: len }, (_, i) => i);
|
|
480
451
|
/**
|
|
481
452
|
* Creates a new array of the specified length, with each position filled with the provided initial value.
|
|
482
453
|
*
|
|
@@ -525,9 +496,9 @@ var Arr;
|
|
|
525
496
|
* @see {@link zeros} for creating arrays filled with zeros
|
|
526
497
|
* @see {@link seq} for creating sequences of consecutive integers
|
|
527
498
|
*/
|
|
499
|
+
Arr.create = (len, init) =>
|
|
528
500
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
529
|
-
|
|
530
|
-
Arr.newArray = Arr.create;
|
|
501
|
+
Array.from({ length: Math.max(0, len) }, () => init);
|
|
531
502
|
/**
|
|
532
503
|
* Creates an array from a generator function.
|
|
533
504
|
*
|
|
@@ -615,216 +586,11 @@ var Arr;
|
|
|
615
586
|
Arr.copy = (array) =>
|
|
616
587
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
617
588
|
array.slice();
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
* - When parameters are runtime values, returns appropriate array types based on sign constraints
|
|
624
|
-
* - Empty arrays are returned for invalid ranges (e.g., start ≥ end with positive step)
|
|
625
|
-
* - Never throws exceptions - invalid parameters result in empty arrays
|
|
626
|
-
*
|
|
627
|
-
* **SmallUint Constraint:** The {@link SmallUint} constraint (0-255) enables precise tuple type inference
|
|
628
|
-
* for compile-time known ranges. This allows TypeScript to compute exact tuple types like `readonly [1, 2, 3, 4]`
|
|
629
|
-
* instead of generic `readonly number[]`.
|
|
630
|
-
*
|
|
631
|
-
* **Type Inference Behavior:**
|
|
632
|
-
* - Literal {@link SmallUint} values with step=1 → precise tuple type (`RangeList<S, E>`)
|
|
633
|
-
* - Non-negative parameters → `readonly SafeUint[]`
|
|
634
|
-
* - Mixed signs or negative parameters → `readonly SafeInt[]`
|
|
635
|
-
* - Runtime values → lose precise typing but maintain safety
|
|
636
|
-
*
|
|
637
|
-
* @template S The type of the start value. When a {@link SmallUint} literal (0-255), enables precise tuple typing.
|
|
638
|
-
* @template E The type of the end value. When a {@link SmallUint} literal (0-255), enables precise tuple typing.
|
|
639
|
-
* @param start The start of the range (inclusive). Must be a safe integer. Supports:
|
|
640
|
-
* - **Literal {@link SmallUint}:** Enables precise tuple types (0-255)
|
|
641
|
-
* - **Runtime {@link SafeInt}:** Fallback to general array types
|
|
642
|
-
* - **Negative values:** Supported for countdown sequences
|
|
643
|
-
* @param end The end of the range (exclusive). Must be a safe integer. Supports:
|
|
644
|
-
* - **Literal {@link SmallUint}:** Enables precise tuple types (0-255)
|
|
645
|
-
* - **Runtime {@link SafeInt}:** Fallback to general array types
|
|
646
|
-
* - **Equal to start:** Results in empty array
|
|
647
|
-
* @param step The step increment (default: 1). Must be a non-zero safe integer.
|
|
648
|
-
* - **Positive step:** generates increasing sequence from start to end
|
|
649
|
-
* - **Negative step:** generates decreasing sequence from start to end
|
|
650
|
-
* - **Zero step:** Not allowed (branded type prevents this)
|
|
651
|
-
* @returns An immutable array containing the arithmetic sequence. Return type depends on parameters:
|
|
652
|
-
* - `RangeList<S, E>` (precise tuple like `readonly [1, 2, 3, 4]`) when `S` and `E` are {@link SmallUint} literals and step is 1
|
|
653
|
-
* - `readonly SafeUint[]` when all parameters are non-negative
|
|
654
|
-
* - `readonly SafeInt[]` for general integer ranges including negative values
|
|
655
|
-
*
|
|
656
|
-
* @example
|
|
657
|
-
* ```typescript
|
|
658
|
-
* // Compile-time known ranges with step=1 produce precise tuple types
|
|
659
|
-
* const range1to4 = Arr.range(1, 5); // readonly [1, 2, 3, 4]
|
|
660
|
-
* const range0to2 = Arr.range(0, 3); // readonly [0, 1, 2]
|
|
661
|
-
* const emptyRange = Arr.range(5, 5); // readonly []
|
|
662
|
-
* const reverseEmpty = Arr.range(5, 1); // readonly [] (invalid with positive step)
|
|
663
|
-
*
|
|
664
|
-
* // SmallUint constraint examples (0-255 for precise typing)
|
|
665
|
-
* const small = Arr.range(0, 10); // readonly [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
666
|
-
* const maxSmall = Arr.range(250, 255); // readonly [250, 251, 252, 253, 254]
|
|
667
|
-
* const beyondSmall = Arr.range(0, 300); // readonly SafeUint[] (loses precision)
|
|
668
|
-
*
|
|
669
|
-
* // Custom step increments
|
|
670
|
-
* const evens = Arr.range(0, 10, 2); // readonly SafeUint[] -> [0, 2, 4, 6, 8]
|
|
671
|
-
* const odds = Arr.range(1, 10, 2); // readonly SafeUint[] -> [1, 3, 5, 7, 9]
|
|
672
|
-
* const countdown = Arr.range(5, 0, -1); // readonly SafeInt[] -> [5, 4, 3, 2, 1]
|
|
673
|
-
* const bigStep = Arr.range(0, 20, 5); // readonly SafeUint[] -> [0, 5, 10, 15]
|
|
674
|
-
*
|
|
675
|
-
* // Edge cases that return empty arrays
|
|
676
|
-
* const singleElement = Arr.range(3, 4); // readonly [3]
|
|
677
|
-
* const invalidRange = Arr.range(10, 5, 2); // readonly [] (start > end with positive step)
|
|
678
|
-
* const invalidReverse = Arr.range(1, 10, -1); // readonly [] (start < end with negative step)
|
|
679
|
-
* const zeroRange = Arr.range(42, 42); // readonly [] (start equals end)
|
|
680
|
-
*
|
|
681
|
-
* // Runtime ranges lose precise typing but maintain safety
|
|
682
|
-
* const dynamicStart = Math.floor(Math.random() * 10) as SafeInt;
|
|
683
|
-
* const dynamicEnd = (dynamicStart + 5) as SafeInt;
|
|
684
|
-
* const dynamicRange = Arr.range(dynamicStart, dynamicEnd); // readonly SafeInt[]
|
|
685
|
-
*
|
|
686
|
-
* // Negative numbers and mixed signs
|
|
687
|
-
* const negativeRange = Arr.range(-5, 5); // readonly SafeInt[] -> [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
|
|
688
|
-
* const negativeCountdown = Arr.range(0, -5, -1); // readonly SafeInt[] -> [0, -1, -2, -3, -4]
|
|
689
|
-
*
|
|
690
|
-
* // Useful for generating index ranges and iteration
|
|
691
|
-
* const indices = Arr.range(0, 10); // readonly [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
|
692
|
-
* const reversedIndices = Arr.range(9, -1, -1); // readonly SafeInt[] -> [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
|
|
693
|
-
*
|
|
694
|
-
* // Functional programming patterns
|
|
695
|
-
* const squares = Arr.range(1, 6).map(x => x * x); // [1, 4, 9, 16, 25]
|
|
696
|
-
* const fibonacci = Arr.range(0, 10).reduce((acc, _, i) => {\n * if (i <= 1) return [...acc, i];\n * return [...acc, acc[i-1] + acc[i-2]];\n * }, [] as number[]); // [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
|
|
697
|
-
*
|
|
698
|
-
* // Type inference examples showing precise vs general types
|
|
699
|
-
* expectType<typeof range1to4, readonly [1, 2, 3, 4]>('='); // Precise tuple
|
|
700
|
-
* expectType<typeof emptyRange, readonly []>('='); // Precise empty tuple
|
|
701
|
-
* expectType<typeof evens, readonly SafeUint[]>('='); // General positive array
|
|
702
|
-
* expectType<typeof countdown, readonly SafeInt[]>('='); // General integer array
|
|
703
|
-
* expectType<typeof negativeRange, readonly SafeInt[]>('='); // General integer array
|
|
704
|
-
* expectType<typeof small, readonly [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]>('='); // Precise tuple
|
|
705
|
-
* expectType<typeof beyondSmall, readonly SafeUint[]>('='); // General array (beyond SmallUint)
|
|
706
|
-
* ```
|
|
707
|
-
*
|
|
708
|
-
* @throws Never throws - invalid ranges simply return empty arrays
|
|
709
|
-
* @see {@link seq} for creating sequences starting from 0
|
|
710
|
-
* @see {@link SmallUint} for understanding the constraint that enables precise typing
|
|
711
|
-
* @see {@link SafeInt} and {@link SafeUint} for the safe integer types used
|
|
712
|
-
*/
|
|
713
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
714
|
-
Arr.range = ((start, end, step = 1) => Array.from(range(start, end, step)));
|
|
715
|
-
// element access
|
|
716
|
-
/**
|
|
717
|
-
* Safely retrieves an element at a given index from an array, returning an {@link Optional}.
|
|
718
|
-
*
|
|
719
|
-
* This function provides type-safe array access with support for negative indexing
|
|
720
|
-
* (e.g., -1 for the last element). Unlike direct array access which can return
|
|
721
|
-
* `undefined` for out-of-bounds indices, this function always returns a well-typed
|
|
722
|
-
* {@link Optional} that explicitly represents the possibility of absence.
|
|
723
|
-
*
|
|
724
|
-
* **Negative Indexing:** Negative indices count from the end of the array:
|
|
725
|
-
* - `-1` refers to the last element
|
|
726
|
-
* - `-2` refers to the second-to-last element, etc.
|
|
727
|
-
*
|
|
728
|
-
* **Curried Usage:** This function supports currying - when called with only an index, it returns
|
|
729
|
-
* a function that can be applied to arrays, making it ideal for use in pipe operations.
|
|
730
|
-
*
|
|
731
|
-
* **Optional Return Type:** The return type is always {@link Optional}<E> which provides:
|
|
732
|
-
* - Type-safe access without `undefined` in your business logic
|
|
733
|
-
* - Explicit handling of \"not found\" cases
|
|
734
|
-
* - Composable error handling with {@link Optional} utilities
|
|
735
|
-
*
|
|
736
|
-
* @template E The type of elements in the array.
|
|
737
|
-
* @param array The array to access (when using direct call syntax).
|
|
738
|
-
* @param index The index to access. Must be a branded `SizeType.ArgArr` (safe integer). Can be:
|
|
739
|
-
* - **Positive integer:** 0-based index from the start (0, 1, 2, ...)
|
|
740
|
-
* - **Negative integer:** index from the end (-1 is last element, -2 is second-to-last, etc.)
|
|
741
|
-
* - **Out of bounds:** any index beyond array bounds returns {@link Optional.None}
|
|
742
|
-
* @returns An {@link Optional}<E> containing:
|
|
743
|
-
* - {@link Optional.Some}<E> with the element if the index is valid
|
|
744
|
-
* - {@link Optional.None} if the index is out of bounds (including empty arrays)
|
|
745
|
-
*
|
|
746
|
-
* @example
|
|
747
|
-
* ```typescript
|
|
748
|
-
* // Direct usage with positive indices
|
|
749
|
-
* const fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry'];
|
|
750
|
-
* const first = Arr.at(fruits, 0); // Optional.Some('apple')
|
|
751
|
-
* const third = Arr.at(fruits, 2); // Optional.Some('cherry')
|
|
752
|
-
* const outOfBounds = Arr.at(fruits, 10); // Optional.None
|
|
753
|
-
*
|
|
754
|
-
* // Negative indexing (accessing from the end)
|
|
755
|
-
* const last = Arr.at(fruits, -1); // Optional.Some('elderberry')
|
|
756
|
-
* const secondLast = Arr.at(fruits, -2); // Optional.Some('date')
|
|
757
|
-
* const negativeOutOfBounds = Arr.at(fruits, -10); // Optional.None
|
|
758
|
-
*
|
|
759
|
-
* // Edge cases
|
|
760
|
-
* const emptyResult = Arr.at([], 0); // Optional.None
|
|
761
|
-
* const negativeOnEmpty = Arr.at([], -1); // Optional.None
|
|
762
|
-
* const singleElement = Arr.at(['only'], 0); // Optional.Some('only')
|
|
763
|
-
* const singleNegative = Arr.at(['only'], -1); // Optional.Some('only')
|
|
764
|
-
*
|
|
765
|
-
* // Safe access pattern with type-safe unwrapping
|
|
766
|
-
* const maybeElement = Arr.at(fruits, 2);
|
|
767
|
-
* if (Optional.isSome(maybeElement)) {
|
|
768
|
-
* console.log(`Found: ${maybeElement.value}`); // Type-safe access, no undefined
|
|
769
|
-
* } else {
|
|
770
|
-
* console.log('Index out of bounds');
|
|
771
|
-
* }
|
|
772
|
-
*
|
|
773
|
-
* // Alternative unwrapping with default
|
|
774
|
-
* const elementOrDefault = Optional.unwrapOr(Arr.at(fruits, 100), 'not found');
|
|
775
|
-
* console.log(elementOrDefault); // 'not found'
|
|
776
|
-
*
|
|
777
|
-
* // Curried usage for functional composition
|
|
778
|
-
* const getSecondElement = Arr.at(1);
|
|
779
|
-
* const getLastElement = Arr.at(-1);
|
|
780
|
-
* const getMiddleElement = Arr.at(2);
|
|
781
|
-
*
|
|
782
|
-
* const nestedArrays = [
|
|
783
|
-
* [10, 20, 30, 40],
|
|
784
|
-
* [50, 60],
|
|
785
|
-
* [70]
|
|
786
|
-
* ];
|
|
787
|
-
* const secondElements = nestedArrays.map(getSecondElement);
|
|
788
|
-
* // [Optional.Some(20), Optional.None, Optional.None]
|
|
789
|
-
*
|
|
790
|
-
* const lastElements = nestedArrays.map(getLastElement);
|
|
791
|
-
* // [Optional.Some(40), Optional.Some(60), Optional.Some(70)]
|
|
792
|
-
*
|
|
793
|
-
* // Pipe composition for data processing
|
|
794
|
-
* const processArray = (arr: readonly string[]) => pipe(arr)
|
|
795
|
-
* .map(getSecondElement)
|
|
796
|
-
* .map(opt => Optional.map(opt, s => s.toUpperCase()))
|
|
797
|
-
* .map(opt => Optional.unwrapOr(opt, 'MISSING'))
|
|
798
|
-
* .value;
|
|
799
|
-
*
|
|
800
|
-
* console.log(processArray(['a', 'b', 'c'])); // 'B'
|
|
801
|
-
* console.log(processArray(['x'])); // 'MISSING'
|
|
802
|
-
*
|
|
803
|
-
* // Advanced curried usage with transformation pipelines
|
|
804
|
-
* const extractAndProcess = pipe([
|
|
805
|
-
* ['hello', 'world', 'typescript'],
|
|
806
|
-
* ['functional', 'programming'],
|
|
807
|
-
* ['type', 'safety', 'matters', 'most']
|
|
808
|
-
* ])
|
|
809
|
-
* .map(arr => arr.map(getSecondElement))
|
|
810
|
-
* .map(opts => opts.map(opt => Optional.unwrapOr(opt, '[missing]')))
|
|
811
|
-
* .value;
|
|
812
|
-
* // [['world'], ['[missing]'], ['safety']]
|
|
813
|
-
*
|
|
814
|
-
* // Type inference examples
|
|
815
|
-
* expectType<typeof first, Optional<string>>('=');
|
|
816
|
-
* expectType<typeof getSecondElement, <T>(array: readonly T[]) => Optional<T>>('=');
|
|
817
|
-
* expectType<typeof negativeOutOfBounds, Optional<string>>('=');
|
|
818
|
-
* ```
|
|
819
|
-
*
|
|
820
|
-
* @see {@link head} for getting the first element specifically
|
|
821
|
-
* @see {@link last} for getting the last element specifically
|
|
822
|
-
* @see {@link Optional} for working with the returned Optional values
|
|
823
|
-
* @see {@link Optional.unwrapOr} for safe unwrapping with defaults
|
|
824
|
-
* @see {@link Optional.map} for transforming Optional values
|
|
825
|
-
*/
|
|
826
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
827
|
-
Arr.at = ((...args) => {
|
|
589
|
+
function range$1(start, end, step = 1) {
|
|
590
|
+
return Array.from(range(start, end, step));
|
|
591
|
+
}
|
|
592
|
+
Arr.range = range$1;
|
|
593
|
+
function at(...args) {
|
|
828
594
|
switch (args.length) {
|
|
829
595
|
case 2: {
|
|
830
596
|
const [array, index] = args;
|
|
@@ -835,10 +601,11 @@ var Arr;
|
|
|
835
601
|
}
|
|
836
602
|
case 1: {
|
|
837
603
|
const [index] = args;
|
|
838
|
-
return (array) =>
|
|
604
|
+
return (array) => at(array, index);
|
|
839
605
|
}
|
|
840
606
|
}
|
|
841
|
-
}
|
|
607
|
+
}
|
|
608
|
+
Arr.at = at;
|
|
842
609
|
/**
|
|
843
610
|
* Returns the first element of an array wrapped in an Optional.
|
|
844
611
|
*
|
|
@@ -910,11 +677,9 @@ var Arr;
|
|
|
910
677
|
* @see {@link at} for accessing elements at specific indices
|
|
911
678
|
* @see {@link tail} for getting all elements except the first
|
|
912
679
|
*/
|
|
680
|
+
Arr.head = (array) =>
|
|
913
681
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
914
|
-
|
|
915
|
-
const element = array.at(0);
|
|
916
|
-
return element === undefined ? Optional.none : Optional.some(element);
|
|
917
|
-
});
|
|
682
|
+
(array.length === 0 ? Optional.none : Optional.some(array.at(0)));
|
|
918
683
|
/**
|
|
919
684
|
* Returns the last element of an array wrapped in an Optional.
|
|
920
685
|
*
|
|
@@ -995,97 +760,10 @@ var Arr;
|
|
|
995
760
|
* @see {@link at} for accessing elements at specific indices with negative indexing support
|
|
996
761
|
* @see {@link butLast} for getting all elements except the last
|
|
997
762
|
*/
|
|
763
|
+
Arr.last = (array) =>
|
|
998
764
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
return element === undefined ? Optional.none : Optional.some(element);
|
|
1002
|
-
});
|
|
1003
|
-
// slicing
|
|
1004
|
-
/**
|
|
1005
|
-
* Slices an array with automatically clamped start and end indices for safe bounds handling.
|
|
1006
|
-
*
|
|
1007
|
-
* This function provides a safer alternative to `Array.slice()` by automatically clamping
|
|
1008
|
-
* the start and end indices to valid bounds, preventing out-of-bounds access and ensuring
|
|
1009
|
-
* consistent behavior regardless of input values.
|
|
1010
|
-
*
|
|
1011
|
-
* **Clamping Behavior:**
|
|
1012
|
-
* - `start` is clamped to `[0, array.length]`
|
|
1013
|
-
* - `end` is clamped to `[clampedStart, array.length]` (ensuring end ≥ start)
|
|
1014
|
-
* - Invalid ranges (start > end after clamping) return empty arrays
|
|
1015
|
-
* - Negative indices are clamped to 0, large indices are clamped to array.length
|
|
1016
|
-
*
|
|
1017
|
-
* **Curried Usage:** This function supports currying - when called with only start and end
|
|
1018
|
-
* indices, it returns a function that can be applied to arrays.
|
|
1019
|
-
*
|
|
1020
|
-
* @template E The type of elements in the array.
|
|
1021
|
-
* @param array The array to slice (when using direct call syntax).
|
|
1022
|
-
* @param start The start index for the slice (inclusive). Will be clamped to valid bounds.
|
|
1023
|
-
* @param end The end index for the slice (exclusive). Will be clamped to valid bounds.
|
|
1024
|
-
* @returns A new immutable array containing the sliced elements. Always returns a valid array,
|
|
1025
|
-
* never throws for out-of-bounds indices.
|
|
1026
|
-
*
|
|
1027
|
-
* @example
|
|
1028
|
-
* ```typescript
|
|
1029
|
-
* const data = [10, 20, 30, 40, 50];
|
|
1030
|
-
*
|
|
1031
|
-
* // Normal slicing
|
|
1032
|
-
* const middle = Arr.sliceClamped(data, 1, 4); // [20, 30, 40]
|
|
1033
|
-
* const beginning = Arr.sliceClamped(data, 0, 2); // [10, 20]
|
|
1034
|
-
* const end = Arr.sliceClamped(data, 3, 5); // [40, 50]
|
|
1035
|
-
*
|
|
1036
|
-
* // Automatic clamping for out-of-bounds indices
|
|
1037
|
-
* const clampedStart = Arr.sliceClamped(data, -10, 3); // [10, 20, 30] (start clamped to 0)
|
|
1038
|
-
* const clampedEnd = Arr.sliceClamped(data, 2, 100); // [30, 40, 50] (end clamped to length)
|
|
1039
|
-
* const bothClamped = Arr.sliceClamped(data, -5, 100); // [10, 20, 30, 40, 50] (entire array)
|
|
1040
|
-
*
|
|
1041
|
-
* // Invalid ranges become empty arrays
|
|
1042
|
-
* const emptyReversed = Arr.sliceClamped(data, 4, 1); // [] (start > end after clamping)
|
|
1043
|
-
* const emptyAtEnd = Arr.sliceClamped(data, 5, 10); // [] (start at end of array)
|
|
1044
|
-
*
|
|
1045
|
-
* // Edge cases
|
|
1046
|
-
* const emptyArray = Arr.sliceClamped([], 0, 5); // [] (empty input)
|
|
1047
|
-
* const singleElement = Arr.sliceClamped([42], 0, 1); // [42]
|
|
1048
|
-
* const fullCopy = Arr.sliceClamped(data, 0, data.length); // [10, 20, 30, 40, 50]
|
|
1049
|
-
*
|
|
1050
|
-
* // Curried usage for functional composition
|
|
1051
|
-
* const takeFirst3 = Arr.sliceClamped(0, 3);
|
|
1052
|
-
* const getMiddle2 = Arr.sliceClamped(1, 3);
|
|
1053
|
-
*
|
|
1054
|
-
* const arrays = [
|
|
1055
|
-
* [1, 2, 3, 4, 5],
|
|
1056
|
-
* [10, 20],
|
|
1057
|
-
* [100, 200, 300, 400, 500, 600]
|
|
1058
|
-
* ];
|
|
1059
|
-
*
|
|
1060
|
-
* const first3Elements = arrays.map(takeFirst3);
|
|
1061
|
-
* // [[1, 2, 3], [10, 20], [100, 200, 300]]
|
|
1062
|
-
*
|
|
1063
|
-
* const middle2Elements = arrays.map(getMiddle2);
|
|
1064
|
-
* // [[2, 3], [20], [200, 300]]
|
|
1065
|
-
*
|
|
1066
|
-
* // Pipe composition
|
|
1067
|
-
* const result = pipe([1, 2, 3, 4, 5, 6])
|
|
1068
|
-
* .map(takeFirst3)
|
|
1069
|
-
* .map(Arr.sum)
|
|
1070
|
-
* .value; // 6 (sum of [1, 2, 3])
|
|
1071
|
-
*
|
|
1072
|
-
* // Comparison with regular Array.slice (which can throw or behave unexpectedly)
|
|
1073
|
-
* try {
|
|
1074
|
-
* // Regular slice with out-of-bounds - works but may be unintuitive
|
|
1075
|
-
* const regularSlice = data.slice(-10, 100); // [10, 20, 30, 40, 50]
|
|
1076
|
-
* // sliceClamped provides same safe behavior explicitly
|
|
1077
|
-
* const clampedSlice = Arr.sliceClamped(data, -10, 100); // [10, 20, 30, 40, 50]
|
|
1078
|
-
* } catch (error) {
|
|
1079
|
-
* // sliceClamped never throws
|
|
1080
|
-
* }
|
|
1081
|
-
* ```
|
|
1082
|
-
*
|
|
1083
|
-
* @see {@link take} for taking the first N elements
|
|
1084
|
-
* @see {@link skip} for skipping the first N elements
|
|
1085
|
-
* @see {@link takeLast} for taking the last N elements
|
|
1086
|
-
*/
|
|
1087
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1088
|
-
Arr.sliceClamped = ((...args) => {
|
|
765
|
+
(array.length === 0 ? Optional.none : Optional.some(array.at(-1)));
|
|
766
|
+
function sliceClamped(...args) {
|
|
1089
767
|
switch (args.length) {
|
|
1090
768
|
case 3: {
|
|
1091
769
|
const [array, start, end] = args;
|
|
@@ -1096,10 +774,11 @@ var Arr;
|
|
|
1096
774
|
}
|
|
1097
775
|
case 2: {
|
|
1098
776
|
const [start, end] = args;
|
|
1099
|
-
return (array) =>
|
|
777
|
+
return (array) => sliceClamped(array, start, end);
|
|
1100
778
|
}
|
|
1101
779
|
}
|
|
1102
|
-
}
|
|
780
|
+
}
|
|
781
|
+
Arr.sliceClamped = sliceClamped;
|
|
1103
782
|
/**
|
|
1104
783
|
* Returns all elements of an array except the first one.
|
|
1105
784
|
* @template E The type of the array (can be a tuple for more precise typing).
|
|
@@ -1130,342 +809,87 @@ var Arr;
|
|
|
1130
809
|
Arr.butLast = (array) =>
|
|
1131
810
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1132
811
|
(Arr.isEmpty(array) ? [] : array.slice(0, -1));
|
|
1133
|
-
|
|
1134
|
-
* Takes the first N elements from an array.
|
|
1135
|
-
*
|
|
1136
|
-
* - If the array is a tuple, the return type is inferred as a tuple of the first N elements.
|
|
1137
|
-
* - If the array is a NonEmptyArray and N is a SizeType.ArgArrPositive, returns a NonEmptyArray.
|
|
1138
|
-
* - Otherwise, returns a readonly array of up to N elements.
|
|
1139
|
-
*
|
|
1140
|
-
* @template E The type of the array (can be a tuple for more precise typing).
|
|
1141
|
-
* @template N The number of elements to take, constrained to `SmallUint`.
|
|
1142
|
-
* @param array The input array.
|
|
1143
|
-
* @param num The number of elements to take.
|
|
1144
|
-
* @returns A new array containing the first N elements.
|
|
1145
|
-
* @example
|
|
1146
|
-
* ```ts
|
|
1147
|
-
* // Regular usage
|
|
1148
|
-
* Arr.take([1, 2, 3, 4] as const, 2); // [1, 2]
|
|
1149
|
-
*
|
|
1150
|
-
* // Curried usage for pipe composition
|
|
1151
|
-
* const takeFirst3 = Arr.take(3);
|
|
1152
|
-
* const result = pipe([1, 2, 3, 4, 5]).map(takeFirst3).value;
|
|
1153
|
-
* console.log(result); // [1, 2, 3]
|
|
1154
|
-
* ```
|
|
1155
|
-
*/
|
|
1156
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1157
|
-
Arr.take = ((...args) => {
|
|
812
|
+
function take(...args) {
|
|
1158
813
|
switch (args.length) {
|
|
1159
814
|
case 2: {
|
|
1160
815
|
const [array, num] = args;
|
|
1161
|
-
return
|
|
816
|
+
return sliceClamped(array, 0, num);
|
|
1162
817
|
}
|
|
1163
818
|
case 1: {
|
|
1164
819
|
const [num] = args;
|
|
1165
|
-
return (array) =>
|
|
820
|
+
return (array) => take(array, num);
|
|
1166
821
|
}
|
|
1167
822
|
}
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
*
|
|
1172
|
-
* - If the array is a tuple, the return type is inferred as a tuple of the last N elements.
|
|
1173
|
-
* - If the array is a non-empty array and N is a positive integer, returns a non-empty array.
|
|
1174
|
-
* - Otherwise, returns a readonly array of up to N elements.
|
|
1175
|
-
*
|
|
1176
|
-
* @template E The type of the array (can be a tuple for more precise typing).
|
|
1177
|
-
* @template N The number of elements to take, constrained to `SmallUint`.
|
|
1178
|
-
* @param array The input array.
|
|
1179
|
-
* @param num The number of elements to take.
|
|
1180
|
-
* @returns A new array containing the last N elements.
|
|
1181
|
-
* @example
|
|
1182
|
-
* ```ts
|
|
1183
|
-
* // Regular usage
|
|
1184
|
-
* Arr.takeLast([1, 2, 3, 4] as const, 2); // [3, 4]
|
|
1185
|
-
*
|
|
1186
|
-
* // Curried usage for pipe composition
|
|
1187
|
-
* const takeLast2 = Arr.takeLast(2);
|
|
1188
|
-
* const result = pipe([1, 2, 3, 4, 5]).map(takeLast2).value;
|
|
1189
|
-
* console.log(result); // [4, 5]
|
|
1190
|
-
* ```
|
|
1191
|
-
*/
|
|
1192
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1193
|
-
Arr.takeLast = ((...args) => {
|
|
823
|
+
}
|
|
824
|
+
Arr.take = take;
|
|
825
|
+
function takeLast(...args) {
|
|
1194
826
|
switch (args.length) {
|
|
1195
827
|
case 2: {
|
|
1196
828
|
const [array, num] = args;
|
|
1197
|
-
return
|
|
829
|
+
return sliceClamped(array, Uint32.sub(Arr.size(array), num), Arr.size(array));
|
|
1198
830
|
}
|
|
1199
831
|
case 1: {
|
|
1200
832
|
const [num] = args;
|
|
1201
|
-
return (array) =>
|
|
833
|
+
return (array) => takeLast(array, num);
|
|
1202
834
|
}
|
|
1203
835
|
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
*
|
|
1208
|
-
* - If the array is a tuple, the return type is inferred as a tuple with the first N elements removed.
|
|
1209
|
-
* - If the array is a non-empty array and N is a positive integer, returns a readonly array (may be empty).
|
|
1210
|
-
* - Otherwise, returns a readonly array with the first N elements skipped.
|
|
1211
|
-
*
|
|
1212
|
-
* @template E The type of the array (can be a tuple for more precise typing).
|
|
1213
|
-
* @template N The number of elements to skip, constrained to `SmallUint`.
|
|
1214
|
-
* @param array The input array.
|
|
1215
|
-
* @param num The number of elements to skip.
|
|
1216
|
-
* @returns A new array containing the elements after skipping the first N.
|
|
1217
|
-
* @example
|
|
1218
|
-
* ```ts
|
|
1219
|
-
* // Regular usage
|
|
1220
|
-
* Arr.skip([1, 2, 3, 4] as const, 2); // [3, 4]
|
|
1221
|
-
*
|
|
1222
|
-
* // Curried usage for pipe composition
|
|
1223
|
-
* const skipFirst2 = Arr.skip(2);
|
|
1224
|
-
* const result = pipe([1, 2, 3, 4, 5]).map(skipFirst2).value;
|
|
1225
|
-
* console.log(result); // [3, 4, 5]
|
|
1226
|
-
* ```
|
|
1227
|
-
*/
|
|
1228
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1229
|
-
Arr.skip = ((...args) => {
|
|
836
|
+
}
|
|
837
|
+
Arr.takeLast = takeLast;
|
|
838
|
+
function skip(...args) {
|
|
1230
839
|
switch (args.length) {
|
|
1231
840
|
case 2: {
|
|
1232
841
|
const [array, num] = args;
|
|
1233
|
-
return
|
|
842
|
+
return sliceClamped(array, num, Arr.size(array));
|
|
1234
843
|
}
|
|
1235
844
|
case 1: {
|
|
1236
845
|
const [num] = args;
|
|
1237
|
-
return (array) =>
|
|
846
|
+
return (array) => skip(array, num);
|
|
1238
847
|
}
|
|
1239
848
|
}
|
|
1240
|
-
}
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
*
|
|
1244
|
-
* - If the array is a tuple, the return type is inferred as a tuple with the last N elements removed.
|
|
1245
|
-
* - If the array is a non-empty array and N is a positive integer, returns a readonly array (may be empty).
|
|
1246
|
-
* - Otherwise, returns a readonly array with the last N elements skipped.
|
|
1247
|
-
*
|
|
1248
|
-
* @template E The type of the array (can be a tuple for more precise typing).
|
|
1249
|
-
* @template N The number of elements to skip, constrained to `SmallUint`.
|
|
1250
|
-
* @param array The input array.
|
|
1251
|
-
* @param num The number of elements to skip from the end.
|
|
1252
|
-
* @returns A new array containing the elements after skipping the last N.
|
|
1253
|
-
* @example
|
|
1254
|
-
* ```ts
|
|
1255
|
-
* // Regular usage
|
|
1256
|
-
* Arr.skipLast([1, 2, 3, 4] as const, 2); // [1, 2]
|
|
1257
|
-
*
|
|
1258
|
-
* // Curried usage for pipe composition
|
|
1259
|
-
* const skipLast2 = Arr.skipLast(2);
|
|
1260
|
-
* const result = pipe([1, 2, 3, 4, 5]).map(skipLast2).value;
|
|
1261
|
-
* console.log(result); // [1, 2, 3]
|
|
1262
|
-
* ```
|
|
1263
|
-
*/
|
|
1264
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1265
|
-
Arr.skipLast = ((...args) => {
|
|
849
|
+
}
|
|
850
|
+
Arr.skip = skip;
|
|
851
|
+
function skipLast(...args) {
|
|
1266
852
|
switch (args.length) {
|
|
1267
853
|
case 2: {
|
|
1268
854
|
const [array, num] = args;
|
|
1269
|
-
return
|
|
855
|
+
return sliceClamped(array, 0, Uint32.sub(Arr.size(array), num));
|
|
1270
856
|
}
|
|
1271
857
|
case 1: {
|
|
1272
858
|
const [num] = args;
|
|
1273
|
-
return (array) =>
|
|
859
|
+
return (array) => skipLast(array, num);
|
|
1274
860
|
}
|
|
1275
861
|
}
|
|
1276
|
-
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
* - **Negative index:** Treated as invalid (returns original array)
|
|
1294
|
-
*
|
|
1295
|
-
* **Curried Usage:** Supports currying for functional composition - when called with only index and
|
|
1296
|
-
* updater, returns a reusable function that can be applied to arrays.
|
|
1297
|
-
*
|
|
1298
|
-
* @template E The type of elements in the original array.
|
|
1299
|
-
* @template U The type of the value returned by the updater function.
|
|
1300
|
-
* @param array The input array to update. Can be any readonly array.
|
|
1301
|
-
* @param index The index of the element to update. Must be a non-negative {@link SizeType.ArgArrNonNegative}.
|
|
1302
|
-
* - **Valid range:** `0 <= index < array.length`
|
|
1303
|
-
* - **Out of bounds:** Returns original array unchanged
|
|
1304
|
-
* - **Negative values:** Not allowed by type system (non-negative constraint)
|
|
1305
|
-
* @param updater A function `(prev: E) => U` that transforms the existing element:
|
|
1306
|
-
* - **prev:** The current element at the specified index
|
|
1307
|
-
* - **returns:** The new value to place at that index (can be different type)
|
|
1308
|
-
* @returns A new `readonly (E | U)[]` array where:
|
|
1309
|
-
* - All elements except the target index remain unchanged (type `E`)
|
|
1310
|
-
* - The element at the target index is replaced with the updater result (type `U`)
|
|
1311
|
-
* - Type union `E | U` accommodates both original and updated element types
|
|
1312
|
-
* - If index is out of bounds, returns the original array unchanged
|
|
1313
|
-
*
|
|
1314
|
-
* @example
|
|
1315
|
-
* ```typescript
|
|
1316
|
-
* // Basic usage with same type transformation
|
|
1317
|
-
* const numbers = [1, 2, 3, 4, 5];
|
|
1318
|
-
* const doubled = Arr.toUpdated(numbers, 2, x => x * 2);
|
|
1319
|
-
* // readonly number[] -> [1, 2, 6, 4, 5]
|
|
1320
|
-
*
|
|
1321
|
-
* // Type union when updater returns different type
|
|
1322
|
-
* const mixed = Arr.toUpdated(numbers, 1, x => `value: ${x}`);
|
|
1323
|
-
* // readonly (number | string)[] -> [1, 'value: 2', 3, 4, 5]
|
|
1324
|
-
*
|
|
1325
|
-
* // Complex object updates
|
|
1326
|
-
* const users = [
|
|
1327
|
-
* { id: 1, name: 'Alice', active: true },
|
|
1328
|
-
* { id: 2, name: 'Bob', active: false },
|
|
1329
|
-
* { id: 3, name: 'Charlie', active: true }
|
|
1330
|
-
* ];
|
|
1331
|
-
*
|
|
1332
|
-
* const activatedUser = Arr.toUpdated(users, 1, user => ({
|
|
1333
|
-
* ...user,
|
|
1334
|
-
* active: true,
|
|
1335
|
-
* lastUpdated: new Date()
|
|
1336
|
-
* }));
|
|
1337
|
-
* // Bob is now active with lastUpdated field
|
|
1338
|
-
*
|
|
1339
|
-
* // Bounds checking behavior
|
|
1340
|
-
* const safe1 = Arr.toUpdated([1, 2, 3], 10, x => x * 2); // [1, 2, 3] (index out of bounds)
|
|
1341
|
-
* const safe2 = Arr.toUpdated([1, 2, 3], 0, x => x * 2); // [2, 2, 3] (valid index)
|
|
1342
|
-
* const safe3 = Arr.toUpdated([], 0, x => x); // [] (empty array, index out of bounds)
|
|
1343
|
-
*
|
|
1344
|
-
* // Functional transformations
|
|
1345
|
-
* const products = [
|
|
1346
|
-
* { name: 'laptop', price: 1000 },
|
|
1347
|
-
* { name: 'mouse', price: 25 },
|
|
1348
|
-
* { name: 'keyboard', price: 75 }
|
|
1349
|
-
* ];
|
|
1350
|
-
*
|
|
1351
|
-
* const discounted = Arr.toUpdated(products, 0, product => ({
|
|
1352
|
-
* ...product,
|
|
1353
|
-
* price: Math.round(product.price * 0.8), // 20% discount
|
|
1354
|
-
* onSale: true
|
|
1355
|
-
* }));
|
|
1356
|
-
* // First product now has discounted price and onSale flag
|
|
1357
|
-
*
|
|
1358
|
-
* // Curried usage for reusable updates
|
|
1359
|
-
* const doubleAtIndex2 = Arr.toUpdated(2, (x: number) => x * 2);
|
|
1360
|
-
* const capitalizeAtIndex0 = Arr.toUpdated(0, (s: string) => s.toUpperCase());
|
|
1361
|
-
* const markCompleteAtIndex = (index: number) =>
|
|
1362
|
-
* Arr.toUpdated(index, (task: {done: boolean}) => ({...task, done: true}));
|
|
1363
|
-
*
|
|
1364
|
-
* const numberArrays = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
|
|
1365
|
-
* const allDoubled = numberArrays.map(doubleAtIndex2);
|
|
1366
|
-
* // [[1, 2, 6], [4, 5, 12], [7, 8, 18]]
|
|
1367
|
-
*
|
|
1368
|
-
* const words = [['hello', 'world'], ['foo', 'bar'], ['type', 'script']];
|
|
1369
|
-
* const capitalized = words.map(capitalizeAtIndex0);
|
|
1370
|
-
* // [['HELLO', 'world'], ['FOO', 'bar'], ['TYPE', 'script']]
|
|
1371
|
-
*
|
|
1372
|
-
* // Pipe composition for data processing
|
|
1373
|
-
* const processArray = (arr: readonly number[]) => pipe(arr)
|
|
1374
|
-
* .map(Arr.toUpdated(0, x => x * 10)) // Scale first element
|
|
1375
|
-
* .map(Arr.toUpdated(1, x => typeof x === 'number' ? x + 100 : x)) // Add to second if number
|
|
1376
|
-
* .value;
|
|
1377
|
-
*
|
|
1378
|
-
* console.log(processArray([1, 2, 3])); // [10, 102, 3]
|
|
1379
|
-
*
|
|
1380
|
-
* // Multiple sequential updates
|
|
1381
|
-
* const pipeline = (data: readonly number[]) => pipe(data)
|
|
1382
|
-
* .map(Arr.toUpdated(0, x => x * 2))
|
|
1383
|
-
* .map(Arr.toUpdated(1, x => typeof x === 'number' ? x + 10 : x))
|
|
1384
|
-
* .map(Arr.toUpdated(2, x => typeof x === 'number' ? x.toString() : x))
|
|
1385
|
-
* .value;
|
|
1386
|
-
*
|
|
1387
|
-
* console.log(pipeline([1, 2, 3])); // [2, 12, '3'] - readonly (number | string)[]
|
|
1388
|
-
*
|
|
1389
|
-
* // Error-safe updates in data processing
|
|
1390
|
-
* const safeUpdate = <T, U>(
|
|
1391
|
-
* array: readonly T[],
|
|
1392
|
-
* index: number,
|
|
1393
|
-
* updater: (value: T) => U
|
|
1394
|
-
* ) => {
|
|
1395
|
-
* if (index < 0 || index >= array.length) {
|
|
1396
|
-
* console.warn(`Index ${index} out of bounds for array of length ${array.length}`);
|
|
1397
|
-
* return array;
|
|
1398
|
-
* }
|
|
1399
|
-
* return Arr.toUpdated(array, index as SizeType.ArgArrNonNegative, updater);
|
|
1400
|
-
* };
|
|
1401
|
-
*
|
|
1402
|
-
* // Advanced: State management pattern
|
|
1403
|
-
* type AppState = {
|
|
1404
|
-
* users: Array<{id: number, name: string}>;
|
|
1405
|
-
* currentUserId: number;
|
|
1406
|
-
* };
|
|
1407
|
-
*
|
|
1408
|
-
* const updateUserName = (state: AppState, userId: number, newName: string): AppState => {
|
|
1409
|
-
* const userIndex = state.users.findIndex(u => u.id === userId);
|
|
1410
|
-
* if (userIndex === -1) return state;
|
|
1411
|
-
*
|
|
1412
|
-
* return {
|
|
1413
|
-
* ...state,
|
|
1414
|
-
* users: Arr.toUpdated(state.users, userIndex as SizeType.ArgArrNonNegative, user => ({
|
|
1415
|
-
* ...user,
|
|
1416
|
-
* name: newName
|
|
1417
|
-
* }))
|
|
1418
|
-
* };
|
|
1419
|
-
* };
|
|
1420
|
-
*
|
|
1421
|
-
* // Type inference examples showing union types
|
|
1422
|
-
* expectType<typeof doubled, readonly number[]>('='); // Same type
|
|
1423
|
-
* expectType<typeof mixed, readonly (number | string)[]>('='); // Union type
|
|
1424
|
-
* expectType<typeof doubleAtIndex2, <T extends readonly number[]>(array: T) => readonly (number | number)[]>('=');
|
|
1425
|
-
* expectType<typeof safe1, readonly number[]>('='); // Bounds check preserves type
|
|
1426
|
-
* ```
|
|
1427
|
-
*
|
|
1428
|
-
* @see {@link Array.prototype.with} for the native method with different error handling
|
|
1429
|
-
* @see {@link SizeType.ArgArrNonNegative} for the index type constraint
|
|
1430
|
-
* @see Immutable update patterns for functional programming approaches
|
|
1431
|
-
*/
|
|
1432
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1433
|
-
Arr.toUpdated = ((...args) => {
|
|
862
|
+
}
|
|
863
|
+
Arr.skipLast = skipLast;
|
|
864
|
+
function set(...args) {
|
|
865
|
+
switch (args.length) {
|
|
866
|
+
case 3: {
|
|
867
|
+
const [array, index, newValue] = args;
|
|
868
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
869
|
+
return array.with(index, newValue);
|
|
870
|
+
}
|
|
871
|
+
case 2: {
|
|
872
|
+
const [index, newValue] = args;
|
|
873
|
+
return (array) => set(array, index, newValue);
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
Arr.set = set;
|
|
878
|
+
function toUpdated(...args) {
|
|
1434
879
|
switch (args.length) {
|
|
1435
880
|
case 3: {
|
|
1436
881
|
const [array, index, updater] = args;
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-type-assertion
|
|
1440
|
-
array.with(index, updater(array[index]));
|
|
882
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unsafe-type-assertion
|
|
883
|
+
return array.with(index, updater(array[index]));
|
|
1441
884
|
}
|
|
1442
885
|
case 2: {
|
|
1443
886
|
const [index, updater] = args;
|
|
1444
|
-
return (array) =>
|
|
887
|
+
return (array) => toUpdated(array, index, updater);
|
|
1445
888
|
}
|
|
1446
889
|
}
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
* Index can be out of bounds (e.g., negative or greater than length), `toSpliced` handles this.
|
|
1451
|
-
* @template E The type of elements in the array.
|
|
1452
|
-
* @param array The input array.
|
|
1453
|
-
* @param index The index at which to insert the new value.
|
|
1454
|
-
* @param newValue The value to insert.
|
|
1455
|
-
* @returns A new array with the value inserted.
|
|
1456
|
-
* @example
|
|
1457
|
-
* ```ts
|
|
1458
|
-
* // Regular usage
|
|
1459
|
-
* Arr.toInserted([1, 2, 3], 1, 10); // [1, 10, 2, 3]
|
|
1460
|
-
*
|
|
1461
|
-
* // Curried usage for pipe composition
|
|
1462
|
-
* const insertAtStart = Arr.toInserted(0, 99);
|
|
1463
|
-
* const result = pipe([1, 2, 3]).map(insertAtStart).value;
|
|
1464
|
-
* console.log(result); // [99, 1, 2, 3]
|
|
1465
|
-
* ```
|
|
1466
|
-
*/
|
|
1467
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1468
|
-
Arr.toInserted = ((...args) => {
|
|
890
|
+
}
|
|
891
|
+
Arr.toUpdated = toUpdated;
|
|
892
|
+
function toInserted(...args) {
|
|
1469
893
|
switch (args.length) {
|
|
1470
894
|
case 3: {
|
|
1471
895
|
const [array, index, newValue] = args;
|
|
@@ -1474,30 +898,12 @@ var Arr;
|
|
|
1474
898
|
}
|
|
1475
899
|
case 2: {
|
|
1476
900
|
const [index, newValue] = args;
|
|
1477
|
-
return (array) =>
|
|
901
|
+
return (array) => toInserted(array, index, newValue);
|
|
1478
902
|
}
|
|
1479
903
|
}
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
* If index is out of bounds, `toSpliced` handles this (usually by returning a copy).
|
|
1484
|
-
* @template E The type of elements in the array.
|
|
1485
|
-
* @param array The input array.
|
|
1486
|
-
* @param index The index of the element to remove.
|
|
1487
|
-
* @returns A new array with the element removed.
|
|
1488
|
-
* @example
|
|
1489
|
-
* ```ts
|
|
1490
|
-
* // Regular usage
|
|
1491
|
-
* Arr.toRemoved([1, 2, 3], 1); // [1, 3]
|
|
1492
|
-
*
|
|
1493
|
-
* // Curried usage for pipe composition
|
|
1494
|
-
* const removeFirst = Arr.toRemoved(0);
|
|
1495
|
-
* const result = pipe([10, 20, 30]).map(removeFirst).value;
|
|
1496
|
-
* console.log(result); // [20, 30]
|
|
1497
|
-
* ```
|
|
1498
|
-
*/
|
|
1499
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1500
|
-
Arr.toRemoved = ((...args) => {
|
|
904
|
+
}
|
|
905
|
+
Arr.toInserted = toInserted;
|
|
906
|
+
function toRemoved(...args) {
|
|
1501
907
|
switch (args.length) {
|
|
1502
908
|
case 2: {
|
|
1503
909
|
const [array, index] = args;
|
|
@@ -1505,109 +911,53 @@ var Arr;
|
|
|
1505
911
|
}
|
|
1506
912
|
case 1: {
|
|
1507
913
|
const [index] = args;
|
|
1508
|
-
return (array) =>
|
|
914
|
+
return (array) => toRemoved(array, index);
|
|
1509
915
|
}
|
|
1510
916
|
}
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
* @template E The type of the input array (can be a tuple).
|
|
1515
|
-
* @template V The type of the value to add.
|
|
1516
|
-
* @param array The input array.
|
|
1517
|
-
* @param newValue The value to add.
|
|
1518
|
-
* @returns A new array with the value added to the end. Type is `readonly [...E, V]`.
|
|
1519
|
-
* @example
|
|
1520
|
-
* ```ts
|
|
1521
|
-
* // Regular usage
|
|
1522
|
-
* Arr.toPushed([1, 2] as const, 3); // [1, 2, 3]
|
|
1523
|
-
*
|
|
1524
|
-
* // Curried usage for pipe composition
|
|
1525
|
-
* const addZero = Arr.toPushed(0);
|
|
1526
|
-
* const result = pipe([1, 2, 3]).map(addZero).value;
|
|
1527
|
-
* console.log(result); // [1, 2, 3, 0]
|
|
1528
|
-
* ```
|
|
1529
|
-
*/
|
|
1530
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1531
|
-
Arr.toPushed = ((...args) => {
|
|
917
|
+
}
|
|
918
|
+
Arr.toRemoved = toRemoved;
|
|
919
|
+
function toPushed(...args) {
|
|
1532
920
|
switch (args.length) {
|
|
1533
921
|
case 2: {
|
|
1534
922
|
const [array, newValue] = args;
|
|
923
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1535
924
|
return array.toSpliced(array.length, 0, newValue);
|
|
1536
925
|
}
|
|
1537
926
|
case 1: {
|
|
1538
927
|
const [newValue] = args;
|
|
1539
|
-
return (array) =>
|
|
928
|
+
return (array) => toPushed(array, newValue);
|
|
1540
929
|
}
|
|
1541
930
|
}
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
* @template E The type of the input array (can be a tuple).
|
|
1546
|
-
* @template V The type of the value to add.
|
|
1547
|
-
* @param array The input array.
|
|
1548
|
-
* @param newValue The value to add.
|
|
1549
|
-
* @returns A new array with the value added to the beginning. Type is `readonly [V, ...E]`.
|
|
1550
|
-
* @example
|
|
1551
|
-
* ```ts
|
|
1552
|
-
* // Regular usage
|
|
1553
|
-
* Arr.toUnshifted([1, 2] as const, 0); // [0, 1, 2]
|
|
1554
|
-
*
|
|
1555
|
-
* // Curried usage for pipe composition
|
|
1556
|
-
* const prependZero = Arr.toUnshifted(0);
|
|
1557
|
-
* const result = pipe([1, 2, 3]).map(prependZero).value;
|
|
1558
|
-
* console.log(result); // [0, 1, 2, 3]
|
|
1559
|
-
* ```
|
|
1560
|
-
*/
|
|
1561
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1562
|
-
Arr.toUnshifted = ((...args) => {
|
|
931
|
+
}
|
|
932
|
+
Arr.toPushed = toPushed;
|
|
933
|
+
function toUnshifted(...args) {
|
|
1563
934
|
switch (args.length) {
|
|
1564
935
|
case 2: {
|
|
1565
936
|
const [array, newValue] = args;
|
|
937
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1566
938
|
return array.toSpliced(0, 0, newValue);
|
|
1567
939
|
}
|
|
1568
940
|
case 1: {
|
|
1569
941
|
const [newValue] = args;
|
|
1570
|
-
return (array) =>
|
|
942
|
+
return (array) => toUnshifted(array, newValue);
|
|
1571
943
|
}
|
|
1572
944
|
}
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
* @param array The array.
|
|
1577
|
-
* @param value The value to fill with.
|
|
1578
|
-
* @param start The start index.
|
|
1579
|
-
* @param end The end index.
|
|
1580
|
-
* @returns A new filled array.
|
|
1581
|
-
* @example
|
|
1582
|
-
* ```typescript
|
|
1583
|
-
* // Regular usage
|
|
1584
|
-
* const arr = [1, 2, 3, 4, 5];
|
|
1585
|
-
* const result = Arr.toFilled(arr, 0, 1, 4);
|
|
1586
|
-
* console.log(result); // [1, 0, 0, 0, 5]
|
|
1587
|
-
*
|
|
1588
|
-
* // Curried usage for pipe composition
|
|
1589
|
-
* const fillWithZeros = Arr.toFilled(0, 1, 3);
|
|
1590
|
-
* const result2 = pipe([1, 2, 3, 4]).map(fillWithZeros).value;
|
|
1591
|
-
* console.log(result2); // [1, 0, 0, 4]
|
|
1592
|
-
* ```
|
|
1593
|
-
*/
|
|
1594
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1595
|
-
Arr.toFilled = ((...args) => {
|
|
945
|
+
}
|
|
946
|
+
Arr.toUnshifted = toUnshifted;
|
|
947
|
+
function toFilled(...args) {
|
|
1596
948
|
switch (args.length) {
|
|
1597
949
|
case 2: {
|
|
1598
950
|
const [array, value] = args;
|
|
1599
|
-
|
|
1600
|
-
cp.fill(value);
|
|
1601
|
-
return cp;
|
|
951
|
+
return Arr.create(asPositiveUint32(array.length), value);
|
|
1602
952
|
}
|
|
1603
953
|
case 1: {
|
|
1604
954
|
const [value] = args;
|
|
1605
|
-
return (array) =>
|
|
955
|
+
return (array) => toFilled(array, value);
|
|
1606
956
|
}
|
|
1607
957
|
}
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1610
|
-
|
|
958
|
+
}
|
|
959
|
+
Arr.toFilled = toFilled;
|
|
960
|
+
function toRangeFilled(...args) {
|
|
1611
961
|
switch (args.length) {
|
|
1612
962
|
case 3: {
|
|
1613
963
|
const [array, value, [start, end]] = args;
|
|
@@ -1617,50 +967,12 @@ var Arr;
|
|
|
1617
967
|
}
|
|
1618
968
|
case 2: {
|
|
1619
969
|
const [value, fillRange] = args;
|
|
1620
|
-
return (array) =>
|
|
970
|
+
return (array) => toRangeFilled(array, value, fillRange);
|
|
1621
971
|
}
|
|
1622
972
|
}
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
* Safely finds the first element in an array that satisfies a predicate function.
|
|
1627
|
-
*
|
|
1628
|
-
* This function provides type-safe searching with no risk of runtime errors. It returns
|
|
1629
|
-
* the first element that matches the predicate wrapped in an Optional, or Optional.None
|
|
1630
|
-
* if no element is found. The predicate receives the element, its index, and the entire array.
|
|
1631
|
-
*
|
|
1632
|
-
* **Curried Usage:** This function supports currying - when called with only a predicate,
|
|
1633
|
-
* it returns a function that can be applied to arrays, making it ideal for functional composition.
|
|
1634
|
-
*
|
|
1635
|
-
* @template E The type of elements in the array.
|
|
1636
|
-
* @param array The array to search through (when using direct call syntax).
|
|
1637
|
-
* @param predicate A function that tests each element. Called with:
|
|
1638
|
-
* - `value`: The current element being tested
|
|
1639
|
-
* - `index`: The index of the current element (branded as `SizeType.Arr`)
|
|
1640
|
-
* - `arr`: The entire array being searched
|
|
1641
|
-
* @returns An `Optional<E>` containing:
|
|
1642
|
-
* - `Optional.Some<E>` with the first matching element if found
|
|
1643
|
-
* - `Optional.None` if no element satisfies the predicate
|
|
1644
|
-
*
|
|
1645
|
-
* @example
|
|
1646
|
-
* ```typescript
|
|
1647
|
-
* const numbers = [1, 2, 3, 4, 5];
|
|
1648
|
-
* const firstEven = Arr.find(numbers, x => x % 2 === 0);
|
|
1649
|
-
* if (Optional.isSome(firstEven)) {
|
|
1650
|
-
* console.log(firstEven.value); // 2
|
|
1651
|
-
* }
|
|
1652
|
-
*
|
|
1653
|
-
* const users = [{ id: 1, name: 'Alice', age: 25 }, { id: 2, name: 'Bob', age: 30 }];
|
|
1654
|
-
* const adult = Arr.find(users, user => user.age >= 30);
|
|
1655
|
-
* // Optional.Some({ id: 2, name: 'Bob', age: 30 })
|
|
1656
|
-
* ```
|
|
1657
|
-
*
|
|
1658
|
-
* @see {@link findIndex} for finding the index instead of the element
|
|
1659
|
-
* @see {@link indexOf} for finding elements by equality
|
|
1660
|
-
* @see {@link Optional} for working with the returned Optional values
|
|
1661
|
-
*/
|
|
1662
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1663
|
-
Arr.find = ((...args) => {
|
|
973
|
+
}
|
|
974
|
+
Arr.toRangeFilled = toRangeFilled;
|
|
975
|
+
function find(...args) {
|
|
1664
976
|
switch (args.length) {
|
|
1665
977
|
case 2: {
|
|
1666
978
|
const [array, predicate] = args;
|
|
@@ -1674,117 +986,31 @@ var Arr;
|
|
|
1674
986
|
}
|
|
1675
987
|
case 1: {
|
|
1676
988
|
const [predicate] = args;
|
|
1677
|
-
return (array) =>
|
|
989
|
+
return (array) => find(array, predicate);
|
|
1678
990
|
}
|
|
1679
991
|
}
|
|
1680
|
-
}
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
* // Basic index finding
|
|
1703
|
-
* const fruits = ['apple', 'banana', 'cherry', 'banana'];
|
|
1704
|
-
* const bananaIndex = Arr.findIndex(fruits, fruit => fruit === 'banana');
|
|
1705
|
-
* if (Optional.isSome(bananaIndex)) {
|
|
1706
|
-
* console.log(bananaIndex.value); // 1 - index of first 'banana'
|
|
1707
|
-
* }
|
|
1708
|
-
*
|
|
1709
|
-
* // Finding with complex conditions
|
|
1710
|
-
* const numbers = [1, 5, 10, 15, 20];
|
|
1711
|
-
* const firstLargeIndex = Arr.findIndex(numbers, (value, index) =>
|
|
1712
|
-
* value > 10 && index > 1
|
|
1713
|
-
* );
|
|
1714
|
-
* // Optional.Some(3) - index of 15 (first value > 10 after index 1)
|
|
1715
|
-
*
|
|
1716
|
-
* // Finding objects by property
|
|
1717
|
-
* const users = [
|
|
1718
|
-
* { id: 1, active: false },
|
|
1719
|
-
* { id: 2, active: true },
|
|
1720
|
-
* { id: 3, active: true }
|
|
1721
|
-
* ];
|
|
1722
|
-
*
|
|
1723
|
-
* const firstActiveIndex = Arr.findIndex(users, user => user.active);
|
|
1724
|
-
* // Optional.Some(1) - index of first active user
|
|
1725
|
-
*
|
|
1726
|
-
* const inactiveAdminIndex = Arr.findIndex(users, user => !user.active && user.id > 5);
|
|
1727
|
-
* // Optional.None - no inactive user with id > 5
|
|
1728
|
-
*
|
|
1729
|
-
* // Empty array handling
|
|
1730
|
-
* const emptyResult = Arr.findIndex([], x => x > 0); // Optional.None
|
|
1731
|
-
*
|
|
1732
|
-
* // Curried usage for functional composition
|
|
1733
|
-
* const findNegativeIndex = Arr.findIndex((x: number) => x < 0);
|
|
1734
|
-
* const findLongStringIndex = Arr.findIndex((s: string) => s.length > 5);
|
|
1735
|
-
*
|
|
1736
|
-
* const datasets = [
|
|
1737
|
-
* [1, 2, -3, 4], // index 2 has negative
|
|
1738
|
-
* [5, 6, 7, 8], // no negative
|
|
1739
|
-
* [-1, 0, 1] // index 0 has negative
|
|
1740
|
-
* ];
|
|
1741
|
-
*
|
|
1742
|
-
* const negativeIndices = datasets.map(findNegativeIndex);
|
|
1743
|
-
* // [Optional.Some(2), Optional.None, Optional.Some(0)]
|
|
1744
|
-
*
|
|
1745
|
-
* // Using found indices for further operations
|
|
1746
|
-
* const data = ['short', 'medium', 'very long string', 'tiny'];
|
|
1747
|
-
* const longStringIndex = Arr.findIndex(data, s => s.length > 8);
|
|
1748
|
-
*
|
|
1749
|
-
* if (Optional.isSome(longStringIndex)) {
|
|
1750
|
-
* const index = longStringIndex.value;
|
|
1751
|
-
* console.log(`Found at position ${index}: ${data[index]}`);
|
|
1752
|
-
* // "Found at position 2: very long string"
|
|
1753
|
-
* }
|
|
1754
|
-
*
|
|
1755
|
-
* // Pipe composition
|
|
1756
|
-
* const result = pipe(['a', 'bb', 'ccc'])
|
|
1757
|
-
* .map(findLongStringIndex)
|
|
1758
|
-
* .map(opt => Optional.unwrapOr(opt, -1))
|
|
1759
|
-
* .value; // 2 (index of 'ccc')
|
|
1760
|
-
*
|
|
1761
|
-
* // Comparing with native findIndex (which returns -1)
|
|
1762
|
-
* const nativeResult = fruits.findIndex(fruit => fruit === 'grape'); // -1
|
|
1763
|
-
* const safeResult = Arr.findIndex(fruits, fruit => fruit === 'grape'); // Optional.None
|
|
1764
|
-
*
|
|
1765
|
-
* // Safe index usage patterns
|
|
1766
|
-
* const maybeIndex = Arr.findIndex(numbers, x => x > 100);
|
|
1767
|
-
* const indexOrDefault = Optional.unwrapOr(maybeIndex, 0); // 0 (not found)
|
|
1768
|
-
*
|
|
1769
|
-
* // Using index for array access
|
|
1770
|
-
* const foundIndex = Arr.findIndex(fruits, f => f.startsWith('c'));
|
|
1771
|
-
* const foundElement = Optional.isSome(foundIndex)
|
|
1772
|
-
* ? fruits[foundIndex.value]
|
|
1773
|
-
* : 'not found';
|
|
1774
|
-
* // 'cherry'
|
|
1775
|
-
*
|
|
1776
|
-
* // Type inference examples
|
|
1777
|
-
* expectType<typeof bananaIndex, Optional<SizeType.Arr>>('=');
|
|
1778
|
-
* expectType<typeof findNegativeIndex, (array: readonly number[]) => Optional<SizeType.Arr>>('=');
|
|
1779
|
-
* ```
|
|
1780
|
-
*
|
|
1781
|
-
* @see {@link find} for finding the element instead of its index
|
|
1782
|
-
* @see {@link indexOf} for finding elements by equality (not predicate)
|
|
1783
|
-
* @see {@link lastIndexOf} for finding the last occurrence
|
|
1784
|
-
* @see {@link Optional} for working with the returned Optional values
|
|
1785
|
-
*/
|
|
1786
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1787
|
-
Arr.findIndex = ((...args) => {
|
|
992
|
+
}
|
|
993
|
+
Arr.find = find;
|
|
994
|
+
function findLast(...args) {
|
|
995
|
+
switch (args.length) {
|
|
996
|
+
case 2: {
|
|
997
|
+
const [array, predicate] = args;
|
|
998
|
+
const foundIndex = array.findLastIndex(
|
|
999
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1000
|
+
predicate);
|
|
1001
|
+
return foundIndex === -1
|
|
1002
|
+
? Optional.none
|
|
1003
|
+
: // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
1004
|
+
Optional.some(array[foundIndex]);
|
|
1005
|
+
}
|
|
1006
|
+
case 1: {
|
|
1007
|
+
const [predicate] = args;
|
|
1008
|
+
return (array) => findLast(array, predicate);
|
|
1009
|
+
}
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
Arr.findLast = findLast;
|
|
1013
|
+
function findIndex(...args) {
|
|
1788
1014
|
switch (args.length) {
|
|
1789
1015
|
case 2: {
|
|
1790
1016
|
const [array, predicate] = args;
|
|
@@ -1794,33 +1020,27 @@ var Arr;
|
|
|
1794
1020
|
}
|
|
1795
1021
|
case 1: {
|
|
1796
1022
|
const [predicate] = args;
|
|
1797
|
-
return (array) =>
|
|
1023
|
+
return (array) => findIndex(array, predicate);
|
|
1798
1024
|
}
|
|
1799
1025
|
}
|
|
1800
|
-
}
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
* const result2 = pipe(['a', 'b', 'c']).map(findB).value;
|
|
1819
|
-
* console.log(Optional.unwrapOr(result2, -1)); // 1
|
|
1820
|
-
* ```
|
|
1821
|
-
*/
|
|
1822
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1823
|
-
Arr.indexOf = ((...args) => {
|
|
1026
|
+
}
|
|
1027
|
+
Arr.findIndex = findIndex;
|
|
1028
|
+
function findLastIndex(...args) {
|
|
1029
|
+
switch (args.length) {
|
|
1030
|
+
case 2: {
|
|
1031
|
+
const [array, predicate] = args;
|
|
1032
|
+
return pipe(array.findLastIndex(
|
|
1033
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1034
|
+
predicate)).map((idx) => (idx >= 0 ? asUint32(idx) : -1)).value;
|
|
1035
|
+
}
|
|
1036
|
+
case 1: {
|
|
1037
|
+
const [predicate] = args;
|
|
1038
|
+
return (array) => findLastIndex(array, predicate);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
Arr.findLastIndex = findLastIndex;
|
|
1043
|
+
function indexOf(...args) {
|
|
1824
1044
|
switch (args.length) {
|
|
1825
1045
|
case 2: {
|
|
1826
1046
|
const [array, searchElement] = args;
|
|
@@ -1829,12 +1049,12 @@ var Arr;
|
|
|
1829
1049
|
}
|
|
1830
1050
|
case 1: {
|
|
1831
1051
|
const [searchElement] = args;
|
|
1832
|
-
return (array) =>
|
|
1052
|
+
return (array) => indexOf(array, searchElement);
|
|
1833
1053
|
}
|
|
1834
1054
|
}
|
|
1835
|
-
}
|
|
1836
|
-
|
|
1837
|
-
|
|
1055
|
+
}
|
|
1056
|
+
Arr.indexOf = indexOf;
|
|
1057
|
+
function indexOfFrom(...args) {
|
|
1838
1058
|
switch (args.length) {
|
|
1839
1059
|
case 3: {
|
|
1840
1060
|
const [array, searchElement, fromIndex] = args;
|
|
@@ -1843,33 +1063,12 @@ var Arr;
|
|
|
1843
1063
|
}
|
|
1844
1064
|
case 2: {
|
|
1845
1065
|
const [searchElement, fromIndex] = args;
|
|
1846
|
-
return (array) =>
|
|
1066
|
+
return (array) => indexOfFrom(array, searchElement, fromIndex);
|
|
1847
1067
|
}
|
|
1848
1068
|
}
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
* @param array The array to search.
|
|
1853
|
-
* @param searchElement The element to search for.
|
|
1854
|
-
* @param fromIndex The index to start searching from (searches backwards).
|
|
1855
|
-
* @returns Optional.Some with the index if found, Optional.None otherwise.
|
|
1856
|
-
* @example
|
|
1857
|
-
* ```typescript
|
|
1858
|
-
* // Regular usage
|
|
1859
|
-
* const arr = ['a', 'b', 'c', 'b'];
|
|
1860
|
-
* const result = Arr.lastIndexOf(arr, 'b');
|
|
1861
|
-
* if (Optional.isSome(result)) {
|
|
1862
|
-
* console.log(result.value); // 3 (branded as SizeType.Arr)
|
|
1863
|
-
* }
|
|
1864
|
-
*
|
|
1865
|
-
* // Curried usage for pipe composition
|
|
1866
|
-
* const findLastB = Arr.lastIndexOf('b');
|
|
1867
|
-
* const result2 = pipe(['a', 'b', 'c', 'b']).map(findLastB).value;
|
|
1868
|
-
* console.log(Optional.unwrapOr(result2, -1)); // 3
|
|
1869
|
-
* ```
|
|
1870
|
-
*/
|
|
1871
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1872
|
-
Arr.lastIndexOf = ((...args) => {
|
|
1069
|
+
}
|
|
1070
|
+
Arr.indexOfFrom = indexOfFrom;
|
|
1071
|
+
function lastIndexOf(...args) {
|
|
1873
1072
|
switch (args.length) {
|
|
1874
1073
|
case 2: {
|
|
1875
1074
|
const [array, searchElement] = args;
|
|
@@ -1878,12 +1077,12 @@ var Arr;
|
|
|
1878
1077
|
}
|
|
1879
1078
|
case 1: {
|
|
1880
1079
|
const [searchElement] = args;
|
|
1881
|
-
return (array) =>
|
|
1080
|
+
return (array) => lastIndexOf(array, searchElement);
|
|
1882
1081
|
}
|
|
1883
1082
|
}
|
|
1884
|
-
}
|
|
1885
|
-
|
|
1886
|
-
|
|
1083
|
+
}
|
|
1084
|
+
Arr.lastIndexOf = lastIndexOf;
|
|
1085
|
+
function lastIndexOfFrom(...args) {
|
|
1887
1086
|
switch (args.length) {
|
|
1888
1087
|
case 3: {
|
|
1889
1088
|
const [array, searchElement, fromIndex] = args;
|
|
@@ -1892,27 +1091,38 @@ var Arr;
|
|
|
1892
1091
|
}
|
|
1893
1092
|
case 2: {
|
|
1894
1093
|
const [searchElement, fromIndex] = args;
|
|
1895
|
-
return (array) =>
|
|
1094
|
+
return (array) => lastIndexOfFrom(array, searchElement, fromIndex);
|
|
1896
1095
|
}
|
|
1897
1096
|
}
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1097
|
+
}
|
|
1098
|
+
Arr.lastIndexOfFrom = lastIndexOfFrom;
|
|
1099
|
+
function every(...args) {
|
|
1100
|
+
switch (args.length) {
|
|
1101
|
+
case 2: {
|
|
1102
|
+
const [array, predicate] = args;
|
|
1103
|
+
return array.every((a, i) => predicate(a, asUint32(i)));
|
|
1104
|
+
}
|
|
1105
|
+
case 1: {
|
|
1106
|
+
const [predicate] = args;
|
|
1107
|
+
return (array) => every(array, predicate);
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
Arr.every = every;
|
|
1112
|
+
function some(...args) {
|
|
1113
|
+
switch (args.length) {
|
|
1114
|
+
case 2: {
|
|
1115
|
+
const [array, predicate] = args;
|
|
1116
|
+
return array.some((a, i) => predicate(a, asUint32(i)));
|
|
1117
|
+
}
|
|
1118
|
+
case 1: {
|
|
1119
|
+
const [predicate] = args;
|
|
1120
|
+
return (array) => some(array, predicate);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
Arr.some = some;
|
|
1125
|
+
function foldl(...args) {
|
|
1916
1126
|
switch (args.length) {
|
|
1917
1127
|
case 3: {
|
|
1918
1128
|
const [array, callbackfn, initialValue] = args;
|
|
@@ -1920,31 +1130,12 @@ var Arr;
|
|
|
1920
1130
|
}
|
|
1921
1131
|
case 2: {
|
|
1922
1132
|
const [callbackfn, initialValue] = args;
|
|
1923
|
-
return (array) =>
|
|
1133
|
+
return (array) => foldl(array, callbackfn, initialValue);
|
|
1924
1134
|
}
|
|
1925
1135
|
}
|
|
1926
|
-
}
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
* This is an alias for `Array.prototype.reduceRight`.
|
|
1930
|
-
* @template E The type of elements in the array.
|
|
1931
|
-
* @template S The type of the accumulated value.
|
|
1932
|
-
* @param array The input array.
|
|
1933
|
-
* @param callbackfn A function to execute on each element in the array: `(previousValue: S, currentValue: A, currentIndex: SizeType.Arr) => S`.
|
|
1934
|
-
* @param initialValue The initial value of the accumulator.
|
|
1935
|
-
* @returns The single value that results from the reduction.
|
|
1936
|
-
* @example
|
|
1937
|
-
* ```ts
|
|
1938
|
-
* // Regular usage
|
|
1939
|
-
* Arr.foldr([1, 2, 3], (sum, n) => sum + n, 0); // 6
|
|
1940
|
-
*
|
|
1941
|
-
* // Curried usage for pipe composition
|
|
1942
|
-
* const concatRight = Arr.foldr((acc: string, curr: string) => curr + acc, '');
|
|
1943
|
-
* const result = pipe(['a', 'b', 'c']).map(concatRight).value;
|
|
1944
|
-
* console.log(result); // "abc"
|
|
1945
|
-
* ```
|
|
1946
|
-
*/
|
|
1947
|
-
Arr.foldr = (...args) => {
|
|
1136
|
+
}
|
|
1137
|
+
Arr.foldl = foldl;
|
|
1138
|
+
function foldr(...args) {
|
|
1948
1139
|
switch (args.length) {
|
|
1949
1140
|
case 3: {
|
|
1950
1141
|
const [array, callbackfn, initialValue] = args;
|
|
@@ -1952,124 +1143,40 @@ var Arr;
|
|
|
1952
1143
|
}
|
|
1953
1144
|
case 2: {
|
|
1954
1145
|
const [callbackfn, initialValue] = args;
|
|
1955
|
-
return (array) =>
|
|
1146
|
+
return (array) => foldr(array, callbackfn, initialValue);
|
|
1956
1147
|
}
|
|
1957
1148
|
}
|
|
1958
|
-
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
* @template E The type of numbers in the array (must extend `number`).
|
|
1962
|
-
* @param array The input array.
|
|
1963
|
-
* @param comparator An optional custom comparator function `(x: N, y: N) => number`. Should return < 0 if x is smaller, 0 if equal, > 0 if x is larger. Defaults to `x - y`.
|
|
1964
|
-
* @returns The minimum value in the array wrapped in Optional.
|
|
1965
|
-
* @example
|
|
1966
|
-
* ```ts
|
|
1967
|
-
* Arr.min([3, 1, 4, 1, 5] as const); // Optional.some(1)
|
|
1968
|
-
* Arr.min([{v:3}, {v:1}], (a,b) => a.v - b.v) // Optional.some({v:1})
|
|
1969
|
-
* Arr.min([]); // Optional.none
|
|
1970
|
-
* ```
|
|
1971
|
-
*/
|
|
1972
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1973
|
-
Arr.min = ((array, comparator) => {
|
|
1149
|
+
}
|
|
1150
|
+
Arr.foldr = foldr;
|
|
1151
|
+
function min(array, comparator) {
|
|
1974
1152
|
if (!Arr.isNonEmpty(array)) {
|
|
1975
1153
|
return Optional.none;
|
|
1976
1154
|
}
|
|
1977
1155
|
const cmp = comparator ?? ((x, y) => Num.from(x) - Num.from(y));
|
|
1978
1156
|
return Optional.some(array.reduce((currentMin, curr) => (cmp(curr, currentMin) < 0 ? curr : currentMin), array[0]));
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
*
|
|
1983
|
-
* - If the array is non-empty, returns the maximum value.
|
|
1984
|
-
* - If the array is empty, returns `Optional.none`.
|
|
1985
|
-
* - You can provide a custom comparator for arbitrary types.
|
|
1986
|
-
*
|
|
1987
|
-
* @template E The type of elements in the array.
|
|
1988
|
-
* @param array The input array.
|
|
1989
|
-
* @param comparator An optional custom comparator function `(x: A, y: A) => number`. Should return < 0 if x is smaller, 0 if equal, > 0 if x is larger. Defaults to numeric comparison.
|
|
1990
|
-
* @returns The maximum value in the array wrapped in Optional.
|
|
1991
|
-
* @example
|
|
1992
|
-
* ```ts
|
|
1993
|
-
* Arr.max([3, 1, 4, 1, 5] as const); // Optional.some(5)
|
|
1994
|
-
* Arr.max([{v:3}, {v:1}], (a,b) => a.v - b.v) // Optional.some({v:3})
|
|
1995
|
-
* Arr.max([]); // Optional.none
|
|
1996
|
-
* ```
|
|
1997
|
-
*/
|
|
1998
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1999
|
-
Arr.max = ((array, comparator) => {
|
|
1157
|
+
}
|
|
1158
|
+
Arr.min = min;
|
|
1159
|
+
function max(array, comparator) {
|
|
2000
1160
|
const cmp = comparator ?? ((x, y) => Num.from(x) - Num.from(y));
|
|
2001
1161
|
// Find max by finding min with an inverted comparator
|
|
2002
|
-
return
|
|
2003
|
-
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
* Arr.minBy(people, p => p.age); // Optional.some({ name: 'Bob', age: 20 })
|
|
2021
|
-
* Arr.minBy([], p => p.age); // Optional.none
|
|
2022
|
-
* ```
|
|
2023
|
-
*/
|
|
2024
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2025
|
-
Arr.minBy = ((array, comparatorValueMapper, comparator) => Arr.min(array, (x, y) => comparator === undefined
|
|
2026
|
-
? Num.from(comparatorValueMapper(x)) -
|
|
2027
|
-
Num.from(comparatorValueMapper(y))
|
|
2028
|
-
: comparator(comparatorValueMapper(x), comparatorValueMapper(y))));
|
|
2029
|
-
/**
|
|
2030
|
-
* Finds the element with the maximum value according to a mapped numeric value.
|
|
2031
|
-
*
|
|
2032
|
-
* - If the array is non-empty, returns the element with the maximum mapped value.
|
|
2033
|
-
* - If the array is empty, returns `Optional.none`.
|
|
2034
|
-
* - You can provide a custom comparator for the mapped values.
|
|
2035
|
-
*
|
|
2036
|
-
* @template E The type of elements in the array.
|
|
2037
|
-
* @template V The type of the value to compare by.
|
|
2038
|
-
* @param array The input array.
|
|
2039
|
-
* @param comparatorValueMapper A function that maps an element to a value for comparison.
|
|
2040
|
-
* @param comparator An optional custom comparator function for the mapped values.
|
|
2041
|
-
* @returns The element with the maximum mapped value wrapped in Optional.
|
|
2042
|
-
* @example
|
|
2043
|
-
* ```ts
|
|
2044
|
-
* const people = [{ name: 'Alice', age: 30 }, { name: 'Bob', age: 20 }] as const;
|
|
2045
|
-
* Arr.maxBy(people, p => p.age); // Optional.some({ name: 'Alice', age: 30 })
|
|
2046
|
-
* Arr.maxBy([], p => p.age); // Optional.none
|
|
2047
|
-
* ```
|
|
2048
|
-
*/
|
|
2049
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2050
|
-
Arr.maxBy = ((array, comparatorValueMapper, comparator) => Arr.max(array, (x, y) => comparator === undefined
|
|
2051
|
-
? Num.from(comparatorValueMapper(x)) -
|
|
2052
|
-
Num.from(comparatorValueMapper(y))
|
|
2053
|
-
: comparator(comparatorValueMapper(x), comparatorValueMapper(y))));
|
|
2054
|
-
/**
|
|
2055
|
-
* Counts the number of elements in an array that satisfy a predicate.
|
|
2056
|
-
* @template E The type of elements in the array.
|
|
2057
|
-
* @param array The input array.
|
|
2058
|
-
* @param predicate A function `(value: A, index: number) => boolean` to test each element for a condition.
|
|
2059
|
-
* @returns The number of elements that satisfy the predicate.
|
|
2060
|
-
* @example
|
|
2061
|
-
* ```ts
|
|
2062
|
-
* // Regular usage
|
|
2063
|
-
* Arr.count([1, 2, 3, 4], (x) => x > 2); // 2
|
|
2064
|
-
*
|
|
2065
|
-
* // Curried usage for pipe composition
|
|
2066
|
-
* const countEvens = Arr.count((x: number) => x % 2 === 0);
|
|
2067
|
-
* const result = pipe([1, 2, 3, 4, 5, 6]).map(countEvens).value;
|
|
2068
|
-
* console.log(result); // 3
|
|
2069
|
-
* ```
|
|
2070
|
-
*/
|
|
2071
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2072
|
-
Arr.count = ((...args) => {
|
|
1162
|
+
return min(array, (x, y) => -cmp(x, y));
|
|
1163
|
+
}
|
|
1164
|
+
Arr.max = max;
|
|
1165
|
+
function minBy(array, comparatorValueMapper, comparator) {
|
|
1166
|
+
return min(array, (x, y) => comparator === undefined
|
|
1167
|
+
? Num.from(comparatorValueMapper(x)) -
|
|
1168
|
+
Num.from(comparatorValueMapper(y))
|
|
1169
|
+
: comparator(comparatorValueMapper(x), comparatorValueMapper(y)));
|
|
1170
|
+
}
|
|
1171
|
+
Arr.minBy = minBy;
|
|
1172
|
+
function maxBy(array, comparatorValueMapper, comparator) {
|
|
1173
|
+
return max(array, (x, y) => comparator === undefined
|
|
1174
|
+
? Num.from(comparatorValueMapper(x)) -
|
|
1175
|
+
Num.from(comparatorValueMapper(y))
|
|
1176
|
+
: comparator(comparatorValueMapper(x), comparatorValueMapper(y)));
|
|
1177
|
+
}
|
|
1178
|
+
Arr.maxBy = maxBy;
|
|
1179
|
+
function count(...args) {
|
|
2073
1180
|
switch (args.length) {
|
|
2074
1181
|
case 2: {
|
|
2075
1182
|
const [array, predicate] = args;
|
|
@@ -2077,32 +1184,12 @@ var Arr;
|
|
|
2077
1184
|
}
|
|
2078
1185
|
case 1: {
|
|
2079
1186
|
const [predicate] = args;
|
|
2080
|
-
return (array) =>
|
|
1187
|
+
return (array) => count(array, predicate);
|
|
2081
1188
|
}
|
|
2082
1189
|
}
|
|
2083
|
-
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
* @template E The type of elements in the array.
|
|
2087
|
-
* @template G The type of the group key (must be a primitive type: `string`, `number`, `boolean`, `symbol`, `bigint`, `null`, or `undefined`).
|
|
2088
|
-
* @param array The input array.
|
|
2089
|
-
* @param grouper A function `(value: A, index: number) => G` that maps an element and its index to a group key.
|
|
2090
|
-
* @returns An `IMap` where keys are group keys and values are the counts of elements in each group.
|
|
2091
|
-
* @example
|
|
2092
|
-
* ```ts
|
|
2093
|
-
* // Regular usage
|
|
2094
|
-
* Arr.countBy([1, 2, 2, 3, 1, 1], (x) => x);
|
|
2095
|
-
* // IMap { 1 => 3, 2 => 2, 3 => 1 }
|
|
2096
|
-
*
|
|
2097
|
-
* // Curried usage for pipe composition
|
|
2098
|
-
* const countByType = Arr.countBy((x: {type: string}) => x.type);
|
|
2099
|
-
* const data = [{type: 'a'}, {type: 'b'}, {type: 'a'}];
|
|
2100
|
-
* const result = pipe(data).map(countByType).value;
|
|
2101
|
-
* // IMap { 'a' => 2, 'b' => 1 }
|
|
2102
|
-
* ```
|
|
2103
|
-
*/
|
|
2104
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2105
|
-
Arr.countBy = ((...args) => {
|
|
1190
|
+
}
|
|
1191
|
+
Arr.count = count;
|
|
1192
|
+
function countBy(...args) {
|
|
2106
1193
|
switch (args.length) {
|
|
2107
1194
|
case 2: {
|
|
2108
1195
|
const [array, grouper] = args;
|
|
@@ -2116,45 +1203,16 @@ var Arr;
|
|
|
2116
1203
|
}
|
|
2117
1204
|
case 1: {
|
|
2118
1205
|
const [grouper] = args;
|
|
2119
|
-
return (array) =>
|
|
1206
|
+
return (array) => countBy(array, grouper);
|
|
2120
1207
|
}
|
|
2121
1208
|
}
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
* Arr.sum([1, 2, 3]); // 6
|
|
2130
|
-
* Arr.sum([]); // 0
|
|
2131
|
-
* Arr.sum([-1, 0, 1]); // 0
|
|
2132
|
-
* ```
|
|
2133
|
-
*/
|
|
2134
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2135
|
-
Arr.sum = ((array) => array.reduce((prev, curr) => prev + curr, 0));
|
|
2136
|
-
/**
|
|
2137
|
-
* Joins array elements into a string.
|
|
2138
|
-
* @param array The array to join.
|
|
2139
|
-
* @param separator The separator string.
|
|
2140
|
-
* @returns Result.Ok with the joined string, Result.Err if the operation throws.
|
|
2141
|
-
* @example
|
|
2142
|
-
* ```typescript
|
|
2143
|
-
* // Regular usage
|
|
2144
|
-
* const arr = ['Hello', 'World'];
|
|
2145
|
-
* const result = Arr.join(arr, ' ');
|
|
2146
|
-
* if (Result.isOk(result)) {
|
|
2147
|
-
* console.log(result.value); // "Hello World"
|
|
2148
|
-
* }
|
|
2149
|
-
*
|
|
2150
|
-
* // Curried usage for pipe composition
|
|
2151
|
-
* const joinWithComma = Arr.join(',');
|
|
2152
|
-
* const result2 = pipe(['a', 'b', 'c']).map(joinWithComma).value;
|
|
2153
|
-
* console.log(Result.unwrapOr(result2, '')); // "a,b,c"
|
|
2154
|
-
* ```
|
|
2155
|
-
*/
|
|
2156
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2157
|
-
Arr.join = ((...args) => {
|
|
1209
|
+
}
|
|
1210
|
+
Arr.countBy = countBy;
|
|
1211
|
+
function sum(array) {
|
|
1212
|
+
return array.reduce((prev, curr) => prev + curr, 0);
|
|
1213
|
+
}
|
|
1214
|
+
Arr.sum = sum;
|
|
1215
|
+
function join(...args) {
|
|
2158
1216
|
switch (args.length) {
|
|
2159
1217
|
case 0:
|
|
2160
1218
|
return (array) => joinImpl(array, undefined);
|
|
@@ -2170,7 +1228,8 @@ var Arr;
|
|
|
2170
1228
|
return joinImpl(array, separator);
|
|
2171
1229
|
}
|
|
2172
1230
|
}
|
|
2173
|
-
}
|
|
1231
|
+
}
|
|
1232
|
+
Arr.join = join;
|
|
2174
1233
|
const joinImpl = (array, separator) => {
|
|
2175
1234
|
try {
|
|
2176
1235
|
const result = array.join(separator);
|
|
@@ -2207,26 +1266,34 @@ var Arr;
|
|
|
2207
1266
|
// Non-null assertion is safe here because `i` is always within bounds of both arrays up to the length of the shorter one.
|
|
2208
1267
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
2209
1268
|
tp(array1[i], array2[i]));
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
1269
|
+
function map(...args) {
|
|
1270
|
+
switch (args.length) {
|
|
1271
|
+
case 2: {
|
|
1272
|
+
const [array, mapFn] = args;
|
|
1273
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1274
|
+
return array.map(mapFn);
|
|
1275
|
+
}
|
|
1276
|
+
case 1: {
|
|
1277
|
+
const [mapFn] = args;
|
|
1278
|
+
return (array) => map(array, mapFn);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
Arr.map = map;
|
|
1283
|
+
function filter(...args) {
|
|
1284
|
+
switch (args.length) {
|
|
1285
|
+
case 2: {
|
|
1286
|
+
const [array, predicate] = args;
|
|
1287
|
+
return array.filter((a, i) => predicate(a, asUint32(i)));
|
|
1288
|
+
}
|
|
1289
|
+
case 1: {
|
|
1290
|
+
const [predicate] = args;
|
|
1291
|
+
return (array) => filter(array, predicate);
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
Arr.filter = filter;
|
|
1296
|
+
function filterNot(...args) {
|
|
2230
1297
|
switch (args.length) {
|
|
2231
1298
|
case 2: {
|
|
2232
1299
|
const [array, predicate] = args;
|
|
@@ -2234,10 +1301,48 @@ var Arr;
|
|
|
2234
1301
|
}
|
|
2235
1302
|
case 1: {
|
|
2236
1303
|
const [predicate] = args;
|
|
2237
|
-
return (array) =>
|
|
1304
|
+
return (array) => filterNot(array, predicate);
|
|
1305
|
+
}
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
Arr.filterNot = filterNot;
|
|
1309
|
+
function flat(...args) {
|
|
1310
|
+
switch (args.length) {
|
|
1311
|
+
case 2: {
|
|
1312
|
+
const [array, depth] = args;
|
|
1313
|
+
return array.flat(depth);
|
|
1314
|
+
}
|
|
1315
|
+
case 1: {
|
|
1316
|
+
const [arrayOrDepth] = args;
|
|
1317
|
+
if (typeof arrayOrDepth === 'number') {
|
|
1318
|
+
const depth = arrayOrDepth;
|
|
1319
|
+
return (array) => flat(array, depth);
|
|
1320
|
+
}
|
|
1321
|
+
else if (arrayOrDepth === undefined) {
|
|
1322
|
+
return (array) => flat(array, 1);
|
|
1323
|
+
}
|
|
1324
|
+
else {
|
|
1325
|
+
return arrayOrDepth.flat(1);
|
|
1326
|
+
}
|
|
1327
|
+
}
|
|
1328
|
+
case 0:
|
|
1329
|
+
return (array) => flat(array, 1);
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
Arr.flat = flat;
|
|
1333
|
+
function flatMap(...args) {
|
|
1334
|
+
switch (args.length) {
|
|
1335
|
+
case 2: {
|
|
1336
|
+
const [array, mapFn] = args;
|
|
1337
|
+
return array.flatMap((a, i) => mapFn(a, asUint32(i)));
|
|
1338
|
+
}
|
|
1339
|
+
case 1: {
|
|
1340
|
+
const [mapFn] = args;
|
|
1341
|
+
return (array) => flatMap(array, mapFn);
|
|
2238
1342
|
}
|
|
2239
1343
|
}
|
|
2240
|
-
}
|
|
1344
|
+
}
|
|
1345
|
+
Arr.flatMap = flatMap;
|
|
2241
1346
|
/**
|
|
2242
1347
|
* Concatenates two arrays.
|
|
2243
1348
|
* @template E1 The type of the first array (can be a tuple).
|
|
@@ -2253,23 +1358,7 @@ var Arr;
|
|
|
2253
1358
|
* ```
|
|
2254
1359
|
*/
|
|
2255
1360
|
Arr.concat = (array1, array2) => [...array1, ...array2];
|
|
2256
|
-
|
|
2257
|
-
* Partitions an array into sub-arrays of a specified size.
|
|
2258
|
-
* The last partition may be smaller if the array length is not a multiple of `chunkSize`.
|
|
2259
|
-
* Returns an empty array if chunkSize < 2.
|
|
2260
|
-
* @template N The size of each partition (must be a number type, typically a literal for precise typing).
|
|
2261
|
-
* @template E The type of elements in the array.
|
|
2262
|
-
* @param array The input array.
|
|
2263
|
-
* @param chunkSize The size of each partition.
|
|
2264
|
-
* @returns An array of arrays, where each inner array has up to `chunkSize` elements.
|
|
2265
|
-
* @example
|
|
2266
|
-
* ```ts
|
|
2267
|
-
* Arr.partition([1, 2, 3, 4, 5, 6], 2); // [[1, 2], [3, 4], [5, 6]]
|
|
2268
|
-
* Arr.partition([1, 2, 3, 4, 5, 6, 7], 3); // [[1, 2, 3], [4, 5, 6], [7]]
|
|
2269
|
-
* ```
|
|
2270
|
-
*/
|
|
2271
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2272
|
-
Arr.partition = ((...args) => {
|
|
1361
|
+
function partition(...args) {
|
|
2273
1362
|
switch (args.length) {
|
|
2274
1363
|
case 2: {
|
|
2275
1364
|
const [array, chunkSize] = args;
|
|
@@ -2279,10 +1368,43 @@ var Arr;
|
|
|
2279
1368
|
}
|
|
2280
1369
|
case 1: {
|
|
2281
1370
|
const [chunkSize] = args;
|
|
2282
|
-
return (array) =>
|
|
1371
|
+
return (array) => partition(array, chunkSize);
|
|
2283
1372
|
}
|
|
2284
1373
|
}
|
|
2285
|
-
}
|
|
1374
|
+
}
|
|
1375
|
+
Arr.partition = partition;
|
|
1376
|
+
/**
|
|
1377
|
+
* Reverses a tuple, preserving element types in their new positions.
|
|
1378
|
+
*
|
|
1379
|
+
* The type system precisely tracks the reversal, so the returned tuple
|
|
1380
|
+
* has its element types in the exact reverse order. This is more precise
|
|
1381
|
+
* than array reversal which loses positional type information.
|
|
1382
|
+
*
|
|
1383
|
+
* @template T - The tuple type to reverse
|
|
1384
|
+
* @param array - The input tuple
|
|
1385
|
+
* @returns A new tuple with elements in reverse order and precise typing
|
|
1386
|
+
*
|
|
1387
|
+
* @example
|
|
1388
|
+
* ```typescript
|
|
1389
|
+
* // Basic reversal
|
|
1390
|
+
* const nums = [1, 2, 3] as const;
|
|
1391
|
+
* const reversed = Arr.toReversed(nums); // readonly [3, 2, 1]
|
|
1392
|
+
*
|
|
1393
|
+
* // Mixed types preserved in reverse positions
|
|
1394
|
+
* const mixed = [1, 'hello', true, null] as const;
|
|
1395
|
+
* const revMixed = Arr.toReversed(mixed);
|
|
1396
|
+
* // readonly [null, true, 'hello', 1]
|
|
1397
|
+
*
|
|
1398
|
+
* // Empty and single-element tuples
|
|
1399
|
+
* const empty = [] as const;
|
|
1400
|
+
* const revEmpty = Arr.toReversed(empty); // readonly []
|
|
1401
|
+
* const single = [42] as const;
|
|
1402
|
+
* const revSingle = Arr.toReversed(single); // readonly [42]
|
|
1403
|
+
* ```
|
|
1404
|
+
*/
|
|
1405
|
+
Arr.toReversed = (array) =>
|
|
1406
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1407
|
+
array.toReversed();
|
|
2286
1408
|
/**
|
|
2287
1409
|
* Sorts an array by a value derived from its elements, using a numeric mapping.
|
|
2288
1410
|
* @template E The type of elements in the array.
|
|
@@ -2299,172 +1421,25 @@ var Arr;
|
|
|
2299
1421
|
* // [{ name: 'Adam', score: 90 }, { name: 'Bob', score: 80 }, { name: 'Eve', score: 70 }]
|
|
2300
1422
|
* ```
|
|
2301
1423
|
*/
|
|
2302
|
-
Arr.
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2306
|
-
comparatorValueMapper(x) -
|
|
2307
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2308
|
-
comparatorValueMapper(y)
|
|
2309
|
-
: comparator(comparatorValueMapper(x), comparatorValueMapper(y)));
|
|
2310
|
-
/**
|
|
2311
|
-
* Returns an array of successively reduced values from an array, starting with an initial value.
|
|
2312
|
-
*
|
|
2313
|
-
* This function creates a \"running tally\" by applying a reducer function to each element and
|
|
2314
|
-
* accumulating the results. Unlike {@link reduce} which returns a single final value, `scan`
|
|
2315
|
-
* returns all intermediate accumulated values, providing visibility into the reduction process.
|
|
2316
|
-
*
|
|
2317
|
-
* **Key Differences from Reduce:**
|
|
2318
|
-
* - {@link reduce}: `[1, 2, 3] -> 6` (final sum only)
|
|
2319
|
-
* - `scan`: `[1, 2, 3] -> [0, 1, 3, 6]` (all intermediate sums including initial value)
|
|
2320
|
-
*
|
|
2321
|
-
* **Guaranteed Non-Empty Return:** The result is always a {@link NonEmptyArray}<S> because it includes
|
|
2322
|
-
* the initial value as the first element, even for empty input arrays. This provides type safety
|
|
2323
|
-
* and eliminates the need for empty array checks.
|
|
2324
|
-
*
|
|
2325
|
-
* **Array Length Relationship:** `result.length === array.length + 1` (includes initial value)
|
|
2326
|
-
*
|
|
2327
|
-
* **Curried Usage:** Supports currying for functional composition - when called with only the reducer
|
|
2328
|
-
* and initial value, returns a reusable function that can be applied to arrays.
|
|
2329
|
-
*
|
|
2330
|
-
* @template E The type of elements in the input array.
|
|
2331
|
-
* @template S The type of the accumulated values and the initial value.
|
|
2332
|
-
* @param array The input array to scan over. Can be empty (result will still contain the initial value).
|
|
2333
|
-
* @param reducer A function `(accumulator: S, currentValue: E, currentIndex: SizeType.Arr) => S` that:
|
|
2334
|
-
* - **accumulator:** The current accumulated value (starts with `init`, then previous results)
|
|
2335
|
-
* - **currentValue:** The current array element being processed
|
|
2336
|
-
* - **currentIndex:** The 0-based index of the current element (typed as {@link SizeType.Arr})
|
|
2337
|
-
* - **returns:** The new accumulated value to include in the result array
|
|
2338
|
-
* @param init The initial accumulated value. Becomes the first element of the result array.
|
|
2339
|
-
* @returns A {@link NonEmptyArray}<S> of accumulated values with length `array.length + 1`:
|
|
2340
|
-
* - `result[0]` is always the `init` value
|
|
2341
|
-
* - `result[i+1]` is the result of applying the reducer to `result[i]` and `array[i]`
|
|
2342
|
-
* - Guaranteed to be non-empty regardless of input array length
|
|
2343
|
-
*
|
|
2344
|
-
* @example
|
|
2345
|
-
* ```typescript
|
|
2346
|
-
* // Basic running sum example
|
|
2347
|
-
* const numbers = [1, 2, 3, 4];
|
|
2348
|
-
* const runningSum = Arr.scan(numbers, (acc, curr) => acc + curr, 0);
|
|
2349
|
-
* // NonEmptyArray<number> -> [0, 1, 3, 6, 10]
|
|
2350
|
-
* // ^ ^ ^ ^ ^
|
|
2351
|
-
* // | | | | └─ 0+1+2+3+4 = 10
|
|
2352
|
-
* // | | | └─ 0+1+2+3 = 6
|
|
2353
|
-
* // | | └─ 0+1+2 = 3
|
|
2354
|
-
* // | └─ 0+1 = 1
|
|
2355
|
-
* // └─ init = 0
|
|
2356
|
-
*
|
|
2357
|
-
* // Difference from reduce
|
|
2358
|
-
* const reduced = numbers.reduce((acc, curr) => acc + curr, 0); // 10 (final only)
|
|
2359
|
-
* const scanned = Arr.scan(numbers, (acc, curr) => acc + curr, 0); // [0, 1, 3, 6, 10] (all steps)
|
|
2360
|
-
*
|
|
2361
|
-
* // Running product
|
|
2362
|
-
* const factorial = Arr.scan([1, 2, 3, 4, 5], (acc, curr) => acc * curr, 1);
|
|
2363
|
-
* // [1, 1, 2, 6, 24, 120] - factorial sequence
|
|
2364
|
-
*
|
|
2365
|
-
* // Running maximum
|
|
2366
|
-
* const temperatures = [20, 25, 18, 30, 22];
|
|
2367
|
-
* const runningMax = Arr.scan(temperatures, (max, temp) => Math.max(max, temp), -Infinity);
|
|
2368
|
-
* // [-Infinity, 20, 25, 25, 30, 30]
|
|
2369
|
-
*
|
|
2370
|
-
* // Building strings incrementally
|
|
2371
|
-
* const words = ['Hello', 'beautiful', 'world'];
|
|
2372
|
-
* const sentences = Arr.scan(words, (sentence, word) => sentence + ' ' + word, '');
|
|
2373
|
-
* // ['', ' Hello', ' Hello beautiful', ' Hello beautiful world']
|
|
2374
|
-
*
|
|
2375
|
-
* // Array accumulation (collecting elements)
|
|
2376
|
-
* const items = ['a', 'b', 'c'];
|
|
2377
|
-
* const growing = Arr.scan(items, (acc, item) => [...acc, item], [] as string[]);
|
|
2378
|
-
* // [[], ['a'], ['a', 'b'], ['a', 'b', 'c']]
|
|
2379
|
-
*
|
|
2380
|
-
* // Financial running balance
|
|
2381
|
-
* const transactions = [100, -20, 50, -30];
|
|
2382
|
-
* const balances = Arr.scan(transactions, (balance, transaction) => balance + transaction, 1000);
|
|
2383
|
-
* // [1000, 1100, 1080, 1130, 1100] - account balance after each transaction
|
|
2384
|
-
*
|
|
2385
|
-
* // Using index information
|
|
2386
|
-
* const letters = ['a', 'b', 'c'];
|
|
2387
|
-
* const indexed = Arr.scan(letters, (acc, letter, index) => acc + `${index}:${letter} `, '');
|
|
2388
|
-
* // ['', '0:a ', '0:a 1:b ', '0:a 1:b 2:c ']
|
|
2389
|
-
*
|
|
2390
|
-
* // Edge cases
|
|
2391
|
-
* const emptyArray: number[] = [];
|
|
2392
|
-
* const emptyResult = Arr.scan(emptyArray, (acc, curr) => acc + curr, 42);
|
|
2393
|
-
* // [42] - NonEmptyArray even for empty input
|
|
2394
|
-
*
|
|
2395
|
-
* const singleElement = Arr.scan([5], (acc, curr) => acc * curr, 2);
|
|
2396
|
-
* // [2, 10] - init value plus one result
|
|
2397
|
-
*
|
|
2398
|
-
* // Complex object accumulation
|
|
2399
|
-
* const sales = [
|
|
2400
|
-
* { product: 'A', amount: 100 },
|
|
2401
|
-
* { product: 'B', amount: 200 },
|
|
2402
|
-
* { product: 'A', amount: 150 }
|
|
2403
|
-
* ];
|
|
2404
|
-
*
|
|
2405
|
-
* const runningSales = Arr.scan(sales, (totals, sale) => ({
|
|
2406
|
-
* ...totals,
|
|
2407
|
-
* [sale.product]: (totals[sale.product] || 0) + sale.amount
|
|
2408
|
-
* }), {} as Record<string, number>);
|
|
2409
|
-
* // [
|
|
2410
|
-
* // {},
|
|
2411
|
-
* // { A: 100 },
|
|
2412
|
-
* // { A: 100, B: 200 },
|
|
2413
|
-
* // { A: 250, B: 200 }
|
|
2414
|
-
* // ]
|
|
2415
|
-
*
|
|
2416
|
-
* // Curried usage for functional composition
|
|
2417
|
-
* const runningSumFn = Arr.scan((acc: number, curr: number) => acc + curr, 0);
|
|
2418
|
-
* const runningProductFn = Arr.scan((acc: number, curr: number) => acc * curr, 1);
|
|
2419
|
-
* const collectingFn = Arr.scan((acc: string[], curr: string) => [...acc, curr], [] as string[]);
|
|
2420
|
-
*
|
|
2421
|
-
* const datasets = [[1, 2, 3], [4, 5], [6, 7, 8, 9]];
|
|
2422
|
-
* const allSums = datasets.map(runningSumFn);
|
|
2423
|
-
* // [
|
|
2424
|
-
* // [0, 1, 3, 6],
|
|
2425
|
-
* // [0, 4, 9],
|
|
2426
|
-
* // [0, 6, 13, 21, 30]
|
|
2427
|
-
* // ]
|
|
2428
|
-
*
|
|
2429
|
-
* // Pipe composition for data analysis
|
|
2430
|
-
* const analysisResult = pipe([10, 20, 30, 40])
|
|
2431
|
-
* .map(runningSumFn)
|
|
2432
|
-
* .map(sums => sums.slice(1)) // Remove initial value to get pure running sums
|
|
2433
|
-
* .map(sums => sums.map((sum, i) => ({ step: i + 1, total: sum })))
|
|
2434
|
-
* .value;
|
|
2435
|
-
* // [{ step: 1, total: 10 }, { step: 2, total: 30 }, { step: 3, total: 60 }, { step: 4, total: 100 }]
|
|
2436
|
-
*
|
|
2437
|
-
* // Advanced: State machine simulation
|
|
2438
|
-
* type State = 'idle' | 'loading' | 'success' | 'error';
|
|
2439
|
-
* type Event = 'start' | 'complete' | 'fail' | 'reset';
|
|
2440
|
-
*
|
|
2441
|
-
* const events: Event[] = ['start', 'complete', 'reset', 'start', 'fail'];
|
|
2442
|
-
* const stateTransition = (state: State, event: Event): State => {
|
|
2443
|
-
* switch (state) {
|
|
2444
|
-
* case 'idle': return event === 'start' ? 'loading' : state;
|
|
2445
|
-
* case 'loading': return event === 'complete' ? 'success' : event === 'fail' ? 'error' : state;
|
|
2446
|
-
* case 'success': return event === 'reset' ? 'idle' : state;
|
|
2447
|
-
* case 'error': return event === 'reset' ? 'idle' : state;
|
|
2448
|
-
* }
|
|
2449
|
-
* };
|
|
2450
|
-
*
|
|
2451
|
-
* const stateHistory = Arr.scan(events, stateTransition, 'idle' as State);
|
|
2452
|
-
* // ['idle', 'loading', 'success', 'idle', 'loading', 'error']
|
|
2453
|
-
*
|
|
2454
|
-
* // Type inference examples
|
|
2455
|
-
* expectType<typeof runningSum, NonEmptyArray<number>>('=');
|
|
2456
|
-
* expectType<typeof emptyResult, NonEmptyArray<number>>('=');
|
|
2457
|
-
* expectType<typeof runningSumFn, <T extends readonly number[]>(array: T) => NonEmptyArray<number>>('=');
|
|
2458
|
-
* expectType<typeof stateHistory, NonEmptyArray<State>>('=');
|
|
2459
|
-
* ```
|
|
2460
|
-
*
|
|
2461
|
-
* @see {@link reduce} for getting only the final accumulated value
|
|
2462
|
-
* @see {@link NonEmptyArray} for understanding the guaranteed non-empty return type
|
|
2463
|
-
* @see {@link SizeType.Arr} for the index parameter type
|
|
2464
|
-
* @see Array.prototype.reduce for the standard reduce function
|
|
2465
|
-
*/
|
|
1424
|
+
Arr.toSorted = (...[array, comparator]) =>
|
|
1425
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1426
|
+
array.toSorted(
|
|
2466
1427
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2467
|
-
|
|
1428
|
+
comparator ??
|
|
1429
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1430
|
+
((x, y) => x - y));
|
|
1431
|
+
function toSortedBy(array, comparatorValueMapper, comparator) {
|
|
1432
|
+
return array.toSorted((x, y) => comparator === undefined
|
|
1433
|
+
? // This branch assumes V is number if comparator is undefined.
|
|
1434
|
+
// The overloads should handle this, but explicit cast might be needed if V is not number.
|
|
1435
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1436
|
+
comparatorValueMapper(x) -
|
|
1437
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1438
|
+
comparatorValueMapper(y)
|
|
1439
|
+
: comparator(comparatorValueMapper(x), comparatorValueMapper(y)));
|
|
1440
|
+
}
|
|
1441
|
+
Arr.toSortedBy = toSortedBy;
|
|
1442
|
+
function scan(...args) {
|
|
2468
1443
|
switch (args.length) {
|
|
2469
1444
|
case 3: {
|
|
2470
1445
|
const [array, reducer, init] = args;
|
|
@@ -2478,161 +1453,12 @@ var Arr;
|
|
|
2478
1453
|
}
|
|
2479
1454
|
case 2: {
|
|
2480
1455
|
const [reducer, init] = args;
|
|
2481
|
-
return (array) =>
|
|
1456
|
+
return (array) => scan(array, reducer, init);
|
|
2482
1457
|
}
|
|
2483
1458
|
}
|
|
2484
|
-
}
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
*
|
|
2488
|
-
* This function categorizes array elements into groups based on a computed key, using the efficient
|
|
2489
|
-
* {@link IMap} data structure for the result. The grouper function receives both the element and its
|
|
2490
|
-
* index, enabling flexible grouping strategies.
|
|
2491
|
-
*
|
|
2492
|
-
* **MapSetKeyType Constraint:** The group key type `G` must extend {@link MapSetKeyType}, which includes
|
|
2493
|
-
* primitive types that can be used as Map keys (string, number, boolean, symbol, null, undefined).
|
|
2494
|
-
* This constraint ensures type safety and efficient key-based operations.
|
|
2495
|
-
*
|
|
2496
|
-
* **IMap Return Type:** Returns an {@link IMap}<G, readonly E[]> where:
|
|
2497
|
-
* - Keys are the computed group identifiers of type `G`
|
|
2498
|
-
* - Values are immutable arrays containing all elements that belong to each group
|
|
2499
|
-
* - Preserves insertion order of first occurrence of each group
|
|
2500
|
-
* - Maintains type safety with precise generic types
|
|
2501
|
-
*
|
|
2502
|
-
* **Curried Usage:** Supports currying for functional composition - when called with only the grouper
|
|
2503
|
-
* function, returns a reusable function that can be applied to arrays.
|
|
2504
|
-
*
|
|
2505
|
-
* @template E The type of elements in the input array.
|
|
2506
|
-
* @template G The type of the group key, constrained to {@link MapSetKeyType} (primitives usable as Map keys).
|
|
2507
|
-
* Must be one of: `string | number | boolean | symbol | null | undefined`
|
|
2508
|
-
* @param array The input array to group. Can be empty (returns empty {@link IMap}).
|
|
2509
|
-
* @param grouper A function `(value: E, index: SizeType.Arr) => G` that computes the group key for each element.
|
|
2510
|
-
* - **value:** The current array element
|
|
2511
|
-
* - **index:** The 0-based index of the element (typed as {@link SizeType.Arr})
|
|
2512
|
-
* - **returns:** The group key (must be {@link MapSetKeyType})
|
|
2513
|
-
* @returns An {@link IMap}<G, readonly E[]> where:
|
|
2514
|
-
* - Keys are unique group identifiers computed by the grouper function
|
|
2515
|
-
* - Values are immutable arrays of elements belonging to each group
|
|
2516
|
-
* - Empty groups are not included (only groups with at least one element)
|
|
2517
|
-
* - Insertion order is preserved based on first occurrence of each group key
|
|
2518
|
-
*
|
|
2519
|
-
* @example
|
|
2520
|
-
* ```typescript
|
|
2521
|
-
* // Basic grouping by object property
|
|
2522
|
-
* const products = [
|
|
2523
|
-
* { type: 'fruit', name: 'apple', price: 1.2 },
|
|
2524
|
-
* { type: 'vegetable', name: 'carrot', price: 0.8 },
|
|
2525
|
-
* { type: 'fruit', name: 'banana', price: 0.9 },
|
|
2526
|
-
* { type: 'vegetable', name: 'broccoli', price: 2.1 },
|
|
2527
|
-
* { type: 'fruit', name: 'orange', price: 1.5 }
|
|
2528
|
-
* ];
|
|
2529
|
-
*
|
|
2530
|
-
* const byType = Arr.groupBy(products, item => item.type);
|
|
2531
|
-
* // IMap<string, readonly Product[]> {
|
|
2532
|
-
* // 'fruit' => [
|
|
2533
|
-
* // { type: 'fruit', name: 'apple', price: 1.2 },
|
|
2534
|
-
* // { type: 'fruit', name: 'banana', price: 0.9 },
|
|
2535
|
-
* // { type: 'fruit', name: 'orange', price: 1.5 }
|
|
2536
|
-
* // ],
|
|
2537
|
-
* // 'vegetable' => [
|
|
2538
|
-
* // { type: 'vegetable', name: 'carrot', price: 0.8 },
|
|
2539
|
-
* // { type: 'vegetable', name: 'broccoli', price: 2.1 }
|
|
2540
|
-
* // ]
|
|
2541
|
-
* // }
|
|
2542
|
-
*
|
|
2543
|
-
* // Access grouped results with IMap methods
|
|
2544
|
-
* const fruits = IMap.get(byType, 'fruit'); // Optional<readonly Product[]>
|
|
2545
|
-
* const fruitCount = Optional.map(fruits, arr => arr.length); // Optional<number>
|
|
2546
|
-
* const fruitNames = Optional.map(fruits, arr => arr.map(p => p.name)); // Optional<string[]>
|
|
2547
|
-
*
|
|
2548
|
-
* // Grouping by computed values
|
|
2549
|
-
* const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
|
2550
|
-
* const byParity = Arr.groupBy(numbers, n => n % 2 === 0 ? 'even' : 'odd');
|
|
2551
|
-
* // IMap<string, readonly number[]> {
|
|
2552
|
-
* // 'odd' => [1, 3, 5, 7, 9],
|
|
2553
|
-
* // 'even' => [2, 4, 6, 8, 10]
|
|
2554
|
-
* // }
|
|
2555
|
-
*
|
|
2556
|
-
* // Grouping by price ranges using index information
|
|
2557
|
-
* const byPriceRange = Arr.groupBy(products, (product, index) => {
|
|
2558
|
-
* const category = product.price < 1.0 ? 'cheap' :
|
|
2559
|
-
* product.price < 2.0 ? 'moderate' : 'expensive';
|
|
2560
|
-
* return `${category}_${index < 2 ? 'early' : 'late'}`;
|
|
2561
|
-
* });
|
|
2562
|
-
*
|
|
2563
|
-
* // MapSetKeyType constraint examples (valid key types)
|
|
2564
|
-
* const byStringKey = Arr.groupBy([1, 2, 3], n => `group_${n}`); // string keys
|
|
2565
|
-
* const byNumberKey = Arr.groupBy(['a', 'b', 'c'], (_, i) => i); // number keys
|
|
2566
|
-
* const byBooleanKey = Arr.groupBy([1, 2, 3, 4], n => n > 2); // boolean keys
|
|
2567
|
-
* const bySymbolKey = Arr.groupBy([1, 2], n => Symbol(n.toString())); // symbol keys
|
|
2568
|
-
*
|
|
2569
|
-
* // Edge cases
|
|
2570
|
-
* const emptyGroup = Arr.groupBy([], x => x); // IMap<never, readonly never[]> (empty)
|
|
2571
|
-
* const singleGroup = Arr.groupBy([1, 2, 3], () => 'all'); // All elements in one group
|
|
2572
|
-
* const uniqueGroups = Arr.groupBy([1, 2, 3], x => x); // Each element in its own group
|
|
2573
|
-
*
|
|
2574
|
-
* // Curried usage for functional composition
|
|
2575
|
-
* const groupByType = Arr.groupBy((item: { type: string }) => item.type);
|
|
2576
|
-
* const groupByLength = Arr.groupBy((str: string) => str.length);
|
|
2577
|
-
* const groupByFirstChar = Arr.groupBy((str: string) => str.charAt(0).toLowerCase());
|
|
2578
|
-
*
|
|
2579
|
-
* const datasets = [
|
|
2580
|
-
* [{ type: 'A' }, { type: 'B' }, { type: 'A' }],
|
|
2581
|
-
* [{ type: 'C' }, { type: 'A' }],
|
|
2582
|
-
* [{ type: 'B' }, { type: 'B' }, { type: 'C' }]
|
|
2583
|
-
* ];
|
|
2584
|
-
* const allGrouped = datasets.map(groupByType);
|
|
2585
|
-
* // Array of IMap instances, each grouped by type
|
|
2586
|
-
*
|
|
2587
|
-
* // Pipe composition for complex data processing
|
|
2588
|
-
* const words = ['apple', 'banana', 'apricot', 'blueberry', 'avocado', 'blackberry'];
|
|
2589
|
-
* const processedGroups = pipe(words)
|
|
2590
|
-
* .map(groupByFirstChar)
|
|
2591
|
-
* .map(groupMap => IMap.map(groupMap, (wordsInGroup, firstLetter) => ({
|
|
2592
|
-
* letter: firstLetter,
|
|
2593
|
-
* count: wordsInGroup.length,
|
|
2594
|
-
* longest: wordsInGroup.reduce((longest, word) =>
|
|
2595
|
-
* word.length > longest.length ? word : longest
|
|
2596
|
-
* )
|
|
2597
|
-
* })))
|
|
2598
|
-
* .value;
|
|
2599
|
-
* // IMap<string, {letter: string, count: number, longest: string}>
|
|
2600
|
-
*
|
|
2601
|
-
* // Advanced: Grouping with complex transformations
|
|
2602
|
-
* const students = [
|
|
2603
|
-
* { name: 'Alice', grade: 85, subject: 'Math' },
|
|
2604
|
-
* { name: 'Bob', grade: 92, subject: 'Science' },
|
|
2605
|
-
* { name: 'Charlie', grade: 78, subject: 'Math' },
|
|
2606
|
-
* { name: 'Diana', grade: 96, subject: 'Science' }
|
|
2607
|
-
* ];
|
|
2608
|
-
*
|
|
2609
|
-
* const byGradeLevel = Arr.groupBy(students, student => {
|
|
2610
|
-
* if (student.grade >= 90) return 'A';
|
|
2611
|
-
* if (student.grade >= 80) return 'B';
|
|
2612
|
-
* return 'C';
|
|
2613
|
-
* });
|
|
2614
|
-
*
|
|
2615
|
-
* // Working with the grouped results
|
|
2616
|
-
* const aStudents = Optional.unwrapOr(IMap.get(byGradeLevel, 'A'), []);
|
|
2617
|
-
* const averageAGrade = aStudents.length > 0
|
|
2618
|
-
* ? aStudents.reduce((sum, s) => sum + s.grade, 0) / aStudents.length
|
|
2619
|
-
* : 0;
|
|
2620
|
-
*
|
|
2621
|
-
* // Type inference examples
|
|
2622
|
-
* expectType<typeof byType, IMap<string, readonly typeof products[number][]>>('=');
|
|
2623
|
-
* expectType<typeof byParity, IMap<string, readonly number[]>>('=');
|
|
2624
|
-
* expectType<typeof groupByType, <T extends {type: string}>(array: readonly T[]) => IMap<string, readonly T[]>>('=');
|
|
2625
|
-
* expectType<typeof emptyGroup, IMap<never, readonly never[]>>('=');
|
|
2626
|
-
* ```
|
|
2627
|
-
*
|
|
2628
|
-
* @see {@link IMap} for working with the returned immutable map
|
|
2629
|
-
* @see {@link MapSetKeyType} for understanding valid key types
|
|
2630
|
-
* @see {@link IMap.get} for safely accessing grouped results
|
|
2631
|
-
* @see {@link IMap.map} for transforming grouped data
|
|
2632
|
-
* @see {@link Optional} for handling potentially missing groups
|
|
2633
|
-
*/
|
|
2634
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2635
|
-
Arr.groupBy = ((...args) => {
|
|
1459
|
+
}
|
|
1460
|
+
Arr.scan = scan;
|
|
1461
|
+
function groupBy(...args) {
|
|
2636
1462
|
switch (args.length) {
|
|
2637
1463
|
case 2: {
|
|
2638
1464
|
const [array, grouper] = args;
|
|
@@ -2652,10 +1478,11 @@ var Arr;
|
|
|
2652
1478
|
}
|
|
2653
1479
|
case 1: {
|
|
2654
1480
|
const [grouper] = args;
|
|
2655
|
-
return (array) =>
|
|
1481
|
+
return (array) => groupBy(array, grouper);
|
|
2656
1482
|
}
|
|
2657
1483
|
}
|
|
2658
|
-
}
|
|
1484
|
+
}
|
|
1485
|
+
Arr.groupBy = groupBy;
|
|
2659
1486
|
/**
|
|
2660
1487
|
* Creates a new array with unique elements from the input array. Order is preserved from the first occurrence.
|
|
2661
1488
|
* Uses `Set` internally for efficient uniqueness checking.
|
|
@@ -2667,7 +1494,9 @@ var Arr;
|
|
|
2667
1494
|
* Arr.uniq([1, 2, 2, 3, 1, 4]); // [1, 2, 3, 4]
|
|
2668
1495
|
* ```
|
|
2669
1496
|
*/
|
|
2670
|
-
Arr.uniq = (array) =>
|
|
1497
|
+
Arr.uniq = (array) =>
|
|
1498
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
1499
|
+
Array.from(new Set(array));
|
|
2671
1500
|
/**
|
|
2672
1501
|
* Creates a new array with unique elements from the input array, based on the values returned by `mapFn`.
|
|
2673
1502
|
*
|
|
@@ -2689,9 +1518,9 @@ var Arr;
|
|
|
2689
1518
|
* Arr.uniqBy(users, user => user.id); // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }]
|
|
2690
1519
|
* ```
|
|
2691
1520
|
*/
|
|
2692
|
-
|
|
2693
|
-
Arr.uniqBy = ((array, mapFn) => {
|
|
1521
|
+
Arr.uniqBy = (array, mapFn) => {
|
|
2694
1522
|
const mut_mappedValues = new Set();
|
|
1523
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
2695
1524
|
return array.filter((val) => {
|
|
2696
1525
|
const mappedValue = mapFn(val);
|
|
2697
1526
|
if (mut_mappedValues.has(mappedValue))
|
|
@@ -2699,7 +1528,7 @@ var Arr;
|
|
|
2699
1528
|
mut_mappedValues.add(mappedValue);
|
|
2700
1529
|
return true;
|
|
2701
1530
|
});
|
|
2702
|
-
}
|
|
1531
|
+
};
|
|
2703
1532
|
// set operations & equality
|
|
2704
1533
|
/**
|
|
2705
1534
|
* Checks if two arrays are equal by performing a shallow comparison of their elements.
|
|
@@ -2842,6 +1671,95 @@ var Arr;
|
|
|
2842
1671
|
}
|
|
2843
1672
|
return mut_result;
|
|
2844
1673
|
};
|
|
1674
|
+
// iterators
|
|
1675
|
+
/**
|
|
1676
|
+
* Returns an iterable of key-value pairs for every entry in the array.
|
|
1677
|
+
*
|
|
1678
|
+
* This function returns an array where each element is a tuple containing the index and value.
|
|
1679
|
+
* The indices are branded as `SizeType.Arr` for type safety.
|
|
1680
|
+
*
|
|
1681
|
+
* @template Ar The exact type of the input array.
|
|
1682
|
+
* @param array The array to get entries from.
|
|
1683
|
+
* @returns An array of `[index, value]` pairs.
|
|
1684
|
+
*
|
|
1685
|
+
* @example
|
|
1686
|
+
* ```typescript
|
|
1687
|
+
* // Direct usage
|
|
1688
|
+
* const fruits = ['apple', 'banana', 'cherry'];
|
|
1689
|
+
* const entries = Arr.entries(fruits); // [[0, 'apple'], [1, 'banana'], [2, 'cherry']]
|
|
1690
|
+
*
|
|
1691
|
+
* // Curried usage
|
|
1692
|
+
* const getEntries = Arr.entries;
|
|
1693
|
+
* const result = getEntries(['a', 'b']); // [[0, 'a'], [1, 'b']]
|
|
1694
|
+
*
|
|
1695
|
+
* // With tuples
|
|
1696
|
+
* const tuple = [10, 20, 30] as const;
|
|
1697
|
+
* const tupleEntries = Arr.entries(tuple); // [[0, 10], [1, 20], [2, 30]]
|
|
1698
|
+
* ```
|
|
1699
|
+
*/
|
|
1700
|
+
function* entries(array) {
|
|
1701
|
+
for (const [index, value] of array.entries()) {
|
|
1702
|
+
yield [asUint32(index), value];
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
Arr.entries = entries;
|
|
1706
|
+
/**
|
|
1707
|
+
* Returns an iterable of values in the array.
|
|
1708
|
+
*
|
|
1709
|
+
* This function is essentially an identity function that returns a copy of the array.
|
|
1710
|
+
* It's included for API completeness and consistency with native Array methods.
|
|
1711
|
+
*
|
|
1712
|
+
* @template Ar The exact type of the input array.
|
|
1713
|
+
* @param array The array to get values from.
|
|
1714
|
+
* @returns A copy of the input array.
|
|
1715
|
+
*
|
|
1716
|
+
* @example
|
|
1717
|
+
* ```typescript
|
|
1718
|
+
* // Direct usage
|
|
1719
|
+
* const numbers = [1, 2, 3];
|
|
1720
|
+
* const values = Arr.values(numbers); // [1, 2, 3]
|
|
1721
|
+
*
|
|
1722
|
+
* // Curried usage
|
|
1723
|
+
* const getValues = Arr.values;
|
|
1724
|
+
* const result = getValues(['a', 'b']); // ['a', 'b']
|
|
1725
|
+
* ```
|
|
1726
|
+
*/
|
|
1727
|
+
function* values(array) {
|
|
1728
|
+
for (const value of array.values()) {
|
|
1729
|
+
yield value;
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
Arr.values = values;
|
|
1733
|
+
/**
|
|
1734
|
+
* Returns an iterable of keys in the array.
|
|
1735
|
+
*
|
|
1736
|
+
* This function returns an array of branded indices (`SizeType.Arr`) for type safety.
|
|
1737
|
+
*
|
|
1738
|
+
* @template Ar The exact type of the input array.
|
|
1739
|
+
* @param array The array to get indices from.
|
|
1740
|
+
* @returns An array of indices.
|
|
1741
|
+
*
|
|
1742
|
+
* @example
|
|
1743
|
+
* ```typescript
|
|
1744
|
+
* // Direct usage
|
|
1745
|
+
* const fruits = ['apple', 'banana', 'cherry'];
|
|
1746
|
+
* const indices = Arr.indices(fruits); // [0, 1, 2]
|
|
1747
|
+
*
|
|
1748
|
+
* // Curried usage
|
|
1749
|
+
* const getIndices = Arr.indices;
|
|
1750
|
+
* const result = getIndices(['a', 'b']); // [0, 1]
|
|
1751
|
+
*
|
|
1752
|
+
* // Empty array
|
|
1753
|
+
* const empty: string[] = [];
|
|
1754
|
+
* const emptyIndices = Arr.indices(empty); // []
|
|
1755
|
+
* ```
|
|
1756
|
+
*/
|
|
1757
|
+
function* indices(array) {
|
|
1758
|
+
for (const key of array.keys()) {
|
|
1759
|
+
yield asUint32(key);
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
Arr.indices = indices;
|
|
2845
1763
|
// aliases
|
|
2846
1764
|
/**
|
|
2847
1765
|
* Alias for `head`. Returns the first element of an array.
|
|
@@ -2857,22 +1775,37 @@ var Arr;
|
|
|
2857
1775
|
* Alias for `skip`. Skips the first N elements of an array.
|
|
2858
1776
|
* @see {@link skip}
|
|
2859
1777
|
*/
|
|
2860
|
-
Arr.drop =
|
|
1778
|
+
Arr.drop = skip;
|
|
2861
1779
|
/**
|
|
2862
1780
|
* Alias for `foldl`. Applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
|
|
2863
1781
|
* @see {@link foldl}
|
|
2864
1782
|
*/
|
|
2865
|
-
Arr.reduce =
|
|
1783
|
+
Arr.reduce = foldl;
|
|
2866
1784
|
/**
|
|
2867
1785
|
* Alias for `foldr`. Applies a function against an accumulator and each element in the array (from right to left) to reduce it to a single value.
|
|
2868
1786
|
* @see {@link foldr}
|
|
2869
1787
|
*/
|
|
2870
|
-
Arr.reduceRight =
|
|
1788
|
+
Arr.reduceRight = foldr;
|
|
2871
1789
|
/**
|
|
2872
1790
|
* Alias for `partition`. Splits an array into chunks of a specified size.
|
|
2873
1791
|
* @see {@link partition}
|
|
2874
1792
|
*/
|
|
2875
|
-
Arr.chunk =
|
|
1793
|
+
Arr.chunk = partition;
|
|
1794
|
+
/**
|
|
1795
|
+
* Alias for `create`. Creates a new array of the specified length, with each position filled with the provided initial value.
|
|
1796
|
+
* @see {@link create}
|
|
1797
|
+
*/
|
|
1798
|
+
Arr.newArray = Arr.create;
|
|
1799
|
+
/**
|
|
1800
|
+
* Alias for `size`. Returns the length of an array.
|
|
1801
|
+
* @see {@link size}
|
|
1802
|
+
*/
|
|
1803
|
+
Arr.length = Arr.size;
|
|
1804
|
+
/**
|
|
1805
|
+
* Alias for `indices`. Returns an iterable of keys in the array.
|
|
1806
|
+
* @see {@link indices}
|
|
1807
|
+
*/
|
|
1808
|
+
Arr.keys = indices;
|
|
2876
1809
|
})(Arr || (Arr = {}));
|
|
2877
1810
|
|
|
2878
1811
|
export { Arr };
|