atomic-fns 1.2.0 → 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 +397 -91
- package/dist/array/index.d.ts +9 -0
- package/dist/array/index.js +9 -0
- package/dist/array/list.d.ts +99 -0
- package/dist/array/list.js +133 -0
- package/dist/array/sets.d.ts +130 -0
- package/dist/array/sets.js +213 -0
- package/dist/async/index.d.ts +6 -0
- package/dist/async/index.js +6 -0
- package/dist/async/retry.d.ts +38 -0
- package/dist/async/retry.js +56 -0
- package/dist/async/sleep.d.ts +42 -0
- package/dist/async/sleep.js +76 -0
- package/dist/collections/bisect.d.ts +103 -0
- package/dist/collections/bisect.js +157 -0
- package/dist/collections/deque.d.ts +67 -97
- package/dist/collections/deque.js +197 -256
- package/dist/collections/entries.d.ts +89 -0
- package/dist/collections/entries.js +131 -0
- package/dist/collections/frozen-set.d.ts +42 -0
- package/dist/collections/frozen-set.js +64 -0
- package/dist/collections/group.d.ts +141 -0
- package/dist/collections/group.js +241 -0
- package/dist/collections/heap.d.ts +64 -0
- package/dist/collections/heap.js +205 -0
- package/dist/collections/index.d.ts +15 -623
- package/dist/collections/index.js +14 -844
- package/dist/collections/internal/arrayKeys.d.ts +19 -0
- package/dist/collections/internal/arrayKeys.js +83 -0
- package/dist/collections/internal/invariants.d.ts +4 -0
- package/dist/collections/internal/invariants.js +12 -0
- package/dist/collections/internal/iterable.d.ts +25 -0
- package/dist/collections/internal/iterable.js +62 -0
- package/dist/collections/iterate.d.ts +162 -0
- package/dist/collections/iterate.js +188 -0
- package/dist/collections/lru-cache.d.ts +58 -0
- package/dist/collections/lru-cache.js +164 -0
- package/dist/collections/order.d.ts +19 -0
- package/dist/collections/order.js +38 -0
- package/dist/collections/shape.d.ts +32 -0
- package/dist/collections/shape.js +86 -0
- package/dist/collections/sorted-map.d.ts +171 -0
- package/dist/collections/sorted-map.js +845 -0
- package/dist/collections/sorted-set.d.ts +103 -0
- package/dist/collections/sorted-set.js +147 -0
- package/dist/collections/splay-tree.d.ts +82 -0
- package/dist/collections/splay-tree.js +354 -0
- package/dist/collections/trie.d.ts +58 -0
- package/dist/collections/trie.js +196 -0
- package/dist/decimal/currency.d.ts +211 -0
- package/dist/decimal/currency.js +321 -0
- package/dist/decimal/decimal.d.ts +299 -0
- package/dist/decimal/decimal.js +660 -0
- package/dist/decimal/index.d.ts +11 -148
- package/dist/decimal/index.js +10 -410
- package/dist/decimal/internal/bits.d.ts +2 -0
- package/dist/decimal/internal/bits.js +7 -0
- package/dist/decimal/internal/echo.d.ts +4 -0
- package/dist/decimal/internal/echo.js +6 -0
- package/dist/decimal/internal/isqrt.d.ts +9 -0
- package/dist/decimal/internal/isqrt.js +34 -0
- package/dist/decimal/internal/locale.d.ts +7 -0
- package/dist/decimal/internal/locale.js +24 -0
- package/dist/decimal/internal/minor-units.d.ts +2 -0
- package/dist/decimal/internal/minor-units.js +33 -0
- package/dist/decimal/internal/pow10.d.ts +24 -0
- package/dist/decimal/internal/pow10.js +96 -0
- package/dist/encoding/base64.d.ts +39 -0
- package/dist/encoding/base64.js +53 -0
- package/dist/encoding/hex.d.ts +23 -0
- package/dist/encoding/hex.js +34 -0
- package/dist/encoding/index.d.ts +6 -0
- package/dist/encoding/index.js +6 -0
- package/dist/function/debounce.d.ts +68 -0
- package/dist/function/debounce.js +203 -0
- package/dist/function/index.d.ts +6 -0
- package/dist/function/index.js +6 -0
- package/dist/function/shared.d.ts +2 -0
- package/dist/function/shared.js +5 -0
- package/dist/function/wrap.d.ts +130 -0
- package/dist/function/wrap.js +113 -0
- package/dist/hash/digest.d.ts +18 -0
- package/dist/hash/digest.js +26 -0
- package/dist/hash/hash.d.ts +22 -0
- package/dist/hash/hash.js +252 -0
- package/dist/hash/hashString.d.ts +13 -0
- package/dist/hash/hashString.js +53 -0
- package/dist/hash/index.d.ts +8 -0
- package/dist/hash/index.js +8 -0
- package/dist/hash/stableStringify.d.ts +19 -0
- package/dist/hash/stableStringify.js +102 -0
- package/dist/id/index.d.ts +7 -0
- package/dist/id/index.js +7 -0
- package/dist/id/nanoid.d.ts +16 -0
- package/dist/id/nanoid.js +65 -0
- package/dist/id/uniqueId.d.ts +14 -0
- package/dist/id/uniqueId.js +20 -0
- package/dist/id/uuid.d.ts +25 -0
- package/dist/id/uuid.js +64 -0
- package/dist/index.d.ts +15 -8
- package/dist/index.js +15 -8
- package/dist/internal/bytes.d.ts +11 -0
- package/dist/internal/bytes.js +33 -0
- package/dist/internal/codec.d.ts +11 -0
- package/dist/internal/codec.js +84 -0
- package/dist/internal/compare.d.ts +10 -0
- package/dist/internal/compare.js +26 -0
- package/dist/internal/crypto.d.ts +5 -0
- package/dist/internal/crypto.js +11 -0
- package/dist/internal/keys.d.ts +12 -0
- package/dist/internal/keys.js +23 -0
- package/dist/internal/kind.d.ts +44 -0
- package/dist/internal/kind.js +139 -0
- package/dist/internal/sparse.d.ts +51 -0
- package/dist/internal/sparse.js +104 -0
- package/dist/internal/text.d.ts +7 -0
- package/dist/internal/text.js +15 -0
- package/dist/internal/timer.d.ts +10 -0
- package/dist/internal/timer.js +17 -0
- package/dist/internal/truncate.d.ts +10 -0
- package/dist/internal/truncate.js +22 -0
- package/dist/internal/walk.d.ts +47 -0
- package/dist/internal/walk.js +100 -0
- package/dist/is/index.d.ts +8 -0
- package/dist/is/index.js +8 -0
- package/dist/is/isArrayLike.d.ts +18 -0
- package/dist/is/isArrayLike.js +25 -0
- package/dist/is/isError.d.ts +13 -0
- package/dist/is/isError.js +18 -0
- package/dist/is/isNil.d.ts +12 -0
- package/dist/is/isNil.js +14 -0
- package/dist/is/isPlainObject.d.ts +15 -0
- package/dist/is/isPlainObject.js +34 -0
- package/dist/number/index.d.ts +7 -0
- package/dist/number/index.js +7 -0
- package/dist/number/round.d.ts +86 -0
- package/dist/number/round.js +130 -0
- package/dist/number/stats.d.ts +52 -0
- package/dist/number/stats.js +115 -0
- package/dist/object/cloneDeep.d.ts +28 -0
- package/dist/object/cloneDeep.js +200 -0
- package/dist/object/index.d.ts +14 -0
- package/dist/object/index.js +13 -0
- package/dist/object/isEqual.d.ts +64 -0
- package/dist/object/isEqual.js +289 -0
- package/dist/object/matches.d.ts +40 -0
- package/dist/object/matches.js +284 -0
- package/dist/object/merge.d.ts +66 -0
- package/dist/object/merge.js +272 -0
- package/dist/object/parsePath.d.ts +22 -0
- package/dist/object/parsePath.js +111 -0
- package/dist/object/path.d.ts +85 -0
- package/dist/object/path.js +208 -0
- package/dist/object/pick.d.ts +91 -0
- package/dist/object/pick.js +180 -0
- package/dist/object/reshape.d.ts +73 -0
- package/dist/object/reshape.js +144 -0
- package/dist/random/index.d.ts +96 -32
- package/dist/random/index.js +215 -53
- package/dist/string/case.d.ts +71 -0
- package/dist/string/case.js +152 -0
- package/dist/string/fold.d.ts +35 -0
- package/dist/string/fold.js +100 -0
- package/dist/string/index.d.ts +6 -187
- package/dist/string/index.js +6 -224
- package/dist/string/truncate.d.ts +25 -0
- package/dist/string/truncate.js +44 -0
- package/dist/string/words.d.ts +27 -0
- package/dist/string/words.js +241 -0
- package/package.json +99 -51
- package/dist/collections/BTree.d.ts +0 -230
- package/dist/collections/BTree.js +0 -1143
- package/dist/collections/Heap.d.ts +0 -69
- package/dist/collections/Heap.js +0 -181
- package/dist/collections/LRUCache.d.ts +0 -83
- package/dist/collections/LRUCache.js +0 -139
- package/dist/collections/SortedMap.d.ts +0 -92
- package/dist/collections/SortedMap.js +0 -131
- package/dist/collections/SortedSet.d.ts +0 -69
- package/dist/collections/SortedSet.js +0 -99
- package/dist/collections/SortedTree.d.ts +0 -103
- package/dist/collections/SortedTree.js +0 -142
- package/dist/collections/SplayTree.d.ts +0 -107
- package/dist/collections/SplayTree.js +0 -351
- package/dist/collections/Trie.d.ts +0 -42
- package/dist/collections/Trie.js +0 -104
- package/dist/collections/abc.d.ts +0 -152
- package/dist/collections/abc.js +0 -39
- package/dist/collections/frozenset.d.ts +0 -19
- package/dist/collections/frozenset.js +0 -33
- package/dist/functools/index.d.ts +0 -106
- package/dist/functools/index.js +0 -203
- package/dist/globals/index.d.ts +0 -268
- package/dist/globals/index.js +0 -447
- package/dist/i18n/currency.d.ts +0 -27
- package/dist/i18n/currency.js +0 -100
- package/dist/i18n/date/index.d.ts +0 -210
- package/dist/i18n/date/index.js +0 -552
- package/dist/i18n/date/utils.d.ts +0 -64
- package/dist/i18n/date/utils.js +0 -192
- package/dist/i18n/duration.d.ts +0 -113
- package/dist/i18n/duration.js +0 -398
- package/dist/i18n/format.d.ts +0 -34
- package/dist/i18n/format.js +0 -378
- package/dist/i18n/index.d.ts +0 -9
- package/dist/i18n/index.js +0 -8
- package/dist/itertools/index.d.ts +0 -251
- package/dist/itertools/index.js +0 -434
- package/dist/math/index.d.ts +0 -79
- package/dist/math/index.js +0 -81
- package/dist/mod.d.ts +0 -1
- package/dist/mod.js +0 -1
- package/dist/operators/index.d.ts +0 -148
- package/dist/operators/index.js +0 -325
- package/dist/types.d.ts +0 -19
- package/dist/types.js +0 -1
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* New objects from old ones: `flattenObject`, `invert`, `mapKeys`, `mapValues`.
|
|
3
|
+
*/
|
|
4
|
+
/** Options of {@link flattenObject}. */
|
|
5
|
+
export interface FlattenOptions {
|
|
6
|
+
/** What joins the keys of nested objects; `'.'` by default. Array indices are written `[0]`. */
|
|
7
|
+
delimiter?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* A one-level object whose keys are the paths to the leaves of `obj`: nested plain-object keys
|
|
11
|
+
* joined by `delimiter`, array elements as `[index]`, so with the default delimiter every key is a
|
|
12
|
+
* path {@link get} reads. An own key of an array that is not an index (the `index` of a RegExp
|
|
13
|
+
* match) is joined by `delimiter` like an object key. A leaf is any value that is not a plain object
|
|
14
|
+
* or array (`null`, a `Date` and class instances included); empty containers give no key.
|
|
15
|
+
* @param obj A plain object or array.
|
|
16
|
+
* @param options `delimiter`, `'.'` by default.
|
|
17
|
+
* @returns A new plain object.
|
|
18
|
+
* @throws {TypeError} when `delimiter` is not a non-empty string, or `obj` is not a plain object or
|
|
19
|
+
* array; for a cycle; for a key that is empty or holds the delimiter, `[` or `]`, since its path
|
|
20
|
+
* would read as another one; and when two paths flatten to the same key (a delimiter of several
|
|
21
|
+
* characters can join different keys alike), which is the same unrepresentable-key case.
|
|
22
|
+
* @throws {RangeError} past 1000 levels of nesting, when shared objects repeat past 250000 units
|
|
23
|
+
* of work, or for output keys over 2^27 characters in all.
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* flattenObject({ a: { b: 1, c: [2, { d: 3 }] } }) // { 'a.b': 1, 'a.c[0]': 2, 'a.c[1].d': 3 }
|
|
27
|
+
* flattenObject({ a: { b: 1 } }, { delimiter: '/' }) // { 'a/b': 1 }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export declare function flattenObject(obj: object, options?: FlattenOptions): Record<string, unknown>;
|
|
31
|
+
/**
|
|
32
|
+
* A new object whose keys are the values of `obj` and whose values are its keys, as lodash's
|
|
33
|
+
* `invert` builds it; a later key wins when two values are the same. A primitive value becomes a
|
|
34
|
+
* key as property keys do, so `1` and `'1'` are one key, and a symbol stays a symbol key.
|
|
35
|
+
* @param obj The object to read; its own enumerable string keys. `null` and `undefined` give `{}`.
|
|
36
|
+
* @returns A new plain object.
|
|
37
|
+
* @throws {TypeError} for a value that is an object or a function, since turning it into a key
|
|
38
|
+
* would call its own `toString`.
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* invert({ a: 'x', b: 'y' }) // { x: 'a', y: 'b' }
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare function invert(obj: object | null | undefined): Record<PropertyKey, string>;
|
|
45
|
+
/**
|
|
46
|
+
* A new object with the values of `obj` under the keys `keyOf` returns.
|
|
47
|
+
* @param obj The object to read; its own enumerable string keys. `null` and `undefined` give `{}`.
|
|
48
|
+
* @param keyOf Called with `(value, key, obj)`; returns the new key.
|
|
49
|
+
* @returns A new plain object; a later entry wins when two keys are the same.
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* mapKeys({ a: 1, b: 2 }, (_value, key) => key.toUpperCase()) // { A: 1, B: 2 }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function mapKeys<V, K extends PropertyKey>(obj: readonly V[] | null | undefined, keyOf: (value: V, key: string, obj: readonly V[]) => K): Record<K, V>;
|
|
56
|
+
/** {@link mapKeys} for an object: `keyOf` gets each own enumerable string key and its value. */
|
|
57
|
+
export declare function mapKeys<T extends object, K extends PropertyKey>(obj: T | null | undefined, keyOf: (value: T[keyof T], key: keyof T & string, obj: T) => K): Record<K, T[keyof T]>;
|
|
58
|
+
/**
|
|
59
|
+
* A new object with the keys of `obj` and the values `valueOf` returns, as lodash's `mapValues`
|
|
60
|
+
* builds it. For an array the result is a plain object keyed by index, not an array.
|
|
61
|
+
* @param obj The object to read; its own enumerable string keys. `null` and `undefined` give `{}`.
|
|
62
|
+
* @param valueOf Called with `(value, key, obj)`; returns the new value.
|
|
63
|
+
* @returns A new plain object.
|
|
64
|
+
* @example
|
|
65
|
+
* ```ts
|
|
66
|
+
* mapValues({ a: 1, b: 2 }, (value) => value * 10) // { a: 10, b: 20 }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function mapValues<V, R>(obj: readonly V[] | null | undefined, valueOf: (value: V, key: string, obj: readonly V[]) => R): Record<number, R>;
|
|
70
|
+
/** {@link mapValues} for an object: the result keeps its own enumerable string keys. */
|
|
71
|
+
export declare function mapValues<T extends object, R>(obj: T | null | undefined, valueOf: (value: T[keyof T], key: keyof T & string, obj: T) => R): {
|
|
72
|
+
[K in keyof T as K extends symbol ? never : K]: R;
|
|
73
|
+
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* New objects from old ones: `flattenObject`, `invert`, `mapKeys`, `mapValues`.
|
|
3
|
+
*/
|
|
4
|
+
import { isPlainObject } from '../is/isPlainObject.js';
|
|
5
|
+
import { isCanonicalArrayIndex } from '../internal/sparse.js';
|
|
6
|
+
import { truncateForError } from '../internal/truncate.js';
|
|
7
|
+
import { Ancestors, guardDepth, RevisitBudget } from '../internal/walk.js';
|
|
8
|
+
import { writeKey } from './parsePath.js';
|
|
9
|
+
const FLATTEN_BUDGET = 250_000;
|
|
10
|
+
const MAX_KEY_CHARS = 2 ** 27;
|
|
11
|
+
/**
|
|
12
|
+
* A one-level object whose keys are the paths to the leaves of `obj`: nested plain-object keys
|
|
13
|
+
* joined by `delimiter`, array elements as `[index]`, so with the default delimiter every key is a
|
|
14
|
+
* path {@link get} reads. An own key of an array that is not an index (the `index` of a RegExp
|
|
15
|
+
* match) is joined by `delimiter` like an object key. A leaf is any value that is not a plain object
|
|
16
|
+
* or array (`null`, a `Date` and class instances included); empty containers give no key.
|
|
17
|
+
* @param obj A plain object or array.
|
|
18
|
+
* @param options `delimiter`, `'.'` by default.
|
|
19
|
+
* @returns A new plain object.
|
|
20
|
+
* @throws {TypeError} when `delimiter` is not a non-empty string, or `obj` is not a plain object or
|
|
21
|
+
* array; for a cycle; for a key that is empty or holds the delimiter, `[` or `]`, since its path
|
|
22
|
+
* would read as another one; and when two paths flatten to the same key (a delimiter of several
|
|
23
|
+
* characters can join different keys alike), which is the same unrepresentable-key case.
|
|
24
|
+
* @throws {RangeError} past 1000 levels of nesting, when shared objects repeat past 250000 units
|
|
25
|
+
* of work, or for output keys over 2^27 characters in all.
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* flattenObject({ a: { b: 1, c: [2, { d: 3 }] } }) // { 'a.b': 1, 'a.c[0]': 2, 'a.c[1].d': 3 }
|
|
29
|
+
* flattenObject({ a: { b: 1 } }, { delimiter: '/' }) // { 'a/b': 1 }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function flattenObject(obj, options = {}) {
|
|
33
|
+
const delimiter = options.delimiter ?? '.';
|
|
34
|
+
if (typeof delimiter !== 'string' || delimiter === '') {
|
|
35
|
+
throw new TypeError('delimiter must be a non-empty string');
|
|
36
|
+
}
|
|
37
|
+
if (!Array.isArray(obj) && !isPlainObject(obj)) {
|
|
38
|
+
throw new TypeError('flattenObject takes a plain object or array');
|
|
39
|
+
}
|
|
40
|
+
return guardDepth(() => {
|
|
41
|
+
const out = {};
|
|
42
|
+
const ancestors = new Ancestors();
|
|
43
|
+
const budget = new RevisitBudget(FLATTEN_BUDGET, `input repeats shared objects beyond ${String(FLATTEN_BUDGET)} containers`);
|
|
44
|
+
const stack = [];
|
|
45
|
+
let chars = 0;
|
|
46
|
+
const emit = (key, value) => {
|
|
47
|
+
chars += key.length;
|
|
48
|
+
if (chars > MAX_KEY_CHARS)
|
|
49
|
+
throw new RangeError(`output keys exceed ${String(MAX_KEY_CHARS)} characters`);
|
|
50
|
+
if (Object.hasOwn(out, key))
|
|
51
|
+
throw new TypeError(`two paths flatten to ${truncateForError(key)}`);
|
|
52
|
+
writeKey(out, key, value);
|
|
53
|
+
};
|
|
54
|
+
const open = (container, prefix) => {
|
|
55
|
+
if (ancestors.has(container))
|
|
56
|
+
throw new TypeError(`cycle at ${truncateForError(prefix)}`);
|
|
57
|
+
const keys = Object.keys(container);
|
|
58
|
+
budget.note(container, keys.length);
|
|
59
|
+
ancestors.enter(container);
|
|
60
|
+
stack.push({ obj: container, prefix, keys, index: 0 });
|
|
61
|
+
};
|
|
62
|
+
try {
|
|
63
|
+
open(obj, '');
|
|
64
|
+
while (stack.length > 0) {
|
|
65
|
+
const frame = stack[stack.length - 1];
|
|
66
|
+
if (frame.index >= frame.keys.length) {
|
|
67
|
+
stack.pop();
|
|
68
|
+
ancestors.leave(frame.obj);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const key = frame.keys[frame.index++];
|
|
72
|
+
const isIndex = Array.isArray(frame.obj) && isCanonicalArrayIndex(key);
|
|
73
|
+
if (!isIndex &&
|
|
74
|
+
(key === '' || key.includes(delimiter) || key.includes('[') || key.includes(']'))) {
|
|
75
|
+
throw new TypeError(`flattenObject cannot represent the key ${truncateForError(key)}`);
|
|
76
|
+
}
|
|
77
|
+
const path = isIndex
|
|
78
|
+
? `${frame.prefix}[${key}]`
|
|
79
|
+
: frame.prefix
|
|
80
|
+
? frame.prefix + delimiter + key
|
|
81
|
+
: key;
|
|
82
|
+
const child = frame.obj[key];
|
|
83
|
+
if (Array.isArray(child) || isPlainObject(child))
|
|
84
|
+
open(child, path);
|
|
85
|
+
else
|
|
86
|
+
emit(path, child);
|
|
87
|
+
}
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
// A throw leaves frames open; leave them so a walk this one runs inside keeps its depth count.
|
|
92
|
+
for (let i = stack.length - 1; i >= 0; i--)
|
|
93
|
+
ancestors.leave(stack[i].obj);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A new object whose keys are the values of `obj` and whose values are its keys, as lodash's
|
|
99
|
+
* `invert` builds it; a later key wins when two values are the same. A primitive value becomes a
|
|
100
|
+
* key as property keys do, so `1` and `'1'` are one key, and a symbol stays a symbol key.
|
|
101
|
+
* @param obj The object to read; its own enumerable string keys. `null` and `undefined` give `{}`.
|
|
102
|
+
* @returns A new plain object.
|
|
103
|
+
* @throws {TypeError} for a value that is an object or a function, since turning it into a key
|
|
104
|
+
* would call its own `toString`.
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* invert({ a: 'x', b: 'y' }) // { x: 'a', y: 'b' }
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
export function invert(obj) {
|
|
111
|
+
const out = {};
|
|
112
|
+
if (obj === null || obj === undefined)
|
|
113
|
+
return out;
|
|
114
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
115
|
+
if ((typeof value === 'object' && value !== null) || typeof value === 'function') {
|
|
116
|
+
throw new TypeError(`invert cannot make a key of the value at ${truncateForError(key)}`);
|
|
117
|
+
}
|
|
118
|
+
writeKey(out, typeof value === 'symbol' ? value : String(value), key);
|
|
119
|
+
}
|
|
120
|
+
return out;
|
|
121
|
+
}
|
|
122
|
+
export function mapKeys(obj, keyOf) {
|
|
123
|
+
const out = {};
|
|
124
|
+
if (obj === null || obj === undefined)
|
|
125
|
+
return out;
|
|
126
|
+
const keyOfEntry = keyOf;
|
|
127
|
+
const record = obj;
|
|
128
|
+
for (const key of Object.keys(record)) {
|
|
129
|
+
const value = record[key];
|
|
130
|
+
writeKey(out, keyOfEntry(value, key, obj), value);
|
|
131
|
+
}
|
|
132
|
+
return out;
|
|
133
|
+
}
|
|
134
|
+
export function mapValues(obj, valueOf) {
|
|
135
|
+
const out = {};
|
|
136
|
+
if (obj === null || obj === undefined)
|
|
137
|
+
return out;
|
|
138
|
+
const valueOfEntry = valueOf;
|
|
139
|
+
const record = obj;
|
|
140
|
+
for (const key of Object.keys(record)) {
|
|
141
|
+
writeKey(out, key, valueOfEntry(record[key], key, obj));
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
package/dist/random/index.d.ts
CHANGED
|
@@ -1,42 +1,106 @@
|
|
|
1
|
+
import type { Collection, CollectionValue } from '../collections/shape.js';
|
|
2
|
+
/** The random source option every function in `fns/random` takes. */
|
|
3
|
+
export interface RandomOptions {
|
|
4
|
+
/** Returns numbers in `[0, 1)`, as `Math.random` does (the default). */
|
|
5
|
+
random?: () => number;
|
|
6
|
+
}
|
|
7
|
+
/** Options for {@link random}. */
|
|
8
|
+
export interface RandomNumberOptions extends RandomOptions {
|
|
9
|
+
/** Return a float in `[min, max)` even when both bounds are integers. */
|
|
10
|
+
float?: boolean;
|
|
11
|
+
}
|
|
1
12
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* @
|
|
13
|
+
* Returns a uniform random integer from `min` to `max`, both included, across any span of safe
|
|
14
|
+
* integers.
|
|
15
|
+
* @param min The lower bound (included).
|
|
16
|
+
* @param max The upper bound (included).
|
|
17
|
+
* @param options `random`, the source of randomness.
|
|
18
|
+
* @returns The integer.
|
|
19
|
+
* @throws {TypeError} when a bound is not a number, `random` is not a function or it returns a
|
|
20
|
+
* value that is not a number.
|
|
21
|
+
* @throws {RangeError} when a bound is not a safe integer, `max < min`, or `random` returns a
|
|
22
|
+
* number outside `[0, 1)`.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* randomInt(1, 6) // a die roll
|
|
26
|
+
* ```
|
|
5
27
|
*/
|
|
28
|
+
export declare function randomInt(min: number, max: number, options?: RandomOptions): number;
|
|
6
29
|
/**
|
|
7
|
-
* Returns a random
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* @
|
|
30
|
+
* Returns a random number from `min` (default 0) to `max` (default 1), as lodash does: an integer
|
|
31
|
+
* with both bounds included, or a float in `[min, max)` when `float` is set or a bound is not a
|
|
32
|
+
* safe integer. One number is `max`.
|
|
33
|
+
* @param min The lower bound, or `max` when it is the only number.
|
|
34
|
+
* @param max The upper bound.
|
|
35
|
+
* @param options `float` and `random`.
|
|
36
|
+
* @returns The random number.
|
|
37
|
+
* @throws {TypeError} when a bound is not a number, `random` is not a function or it returns a
|
|
38
|
+
* value that is not a number.
|
|
39
|
+
* @throws {RangeError} when a bound is not finite, `max < min`, or `random` returns a number
|
|
40
|
+
* outside `[0, 1)`.
|
|
41
|
+
* @example
|
|
42
|
+
* ```ts
|
|
43
|
+
* random(5) // an integer from 0 to 5
|
|
44
|
+
* random(1.5, 2.5) // a float in [1.5, 2.5)
|
|
45
|
+
* random(0, 1, { float: true }) // a float in [0, 1)
|
|
46
|
+
* ```
|
|
11
47
|
*/
|
|
12
|
-
export declare function random(
|
|
48
|
+
export declare function random(options?: RandomNumberOptions): number;
|
|
49
|
+
/** A random number from 0 to `max`. */
|
|
50
|
+
export declare function random(max: number, options?: RandomNumberOptions): number;
|
|
51
|
+
/** A random number from `min` to `max`. */
|
|
52
|
+
export declare function random(min: number, max: number, options?: RandomNumberOptions): number;
|
|
13
53
|
/**
|
|
14
|
-
* Returns a random
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
54
|
+
* Returns a random value of a collection, or `undefined` when it has none. Collections follow the
|
|
55
|
+
* fns/collection shapes: an object gives its own enumerable values, an array its elements (holes
|
|
56
|
+
* skipped), a string its code points, a `Map` or `Set` its values, and any other iterable its
|
|
57
|
+
* items. Arrays and typed arrays read only selected positions unless an array hole triggers a
|
|
58
|
+
* full scan. Sparse arrays may consume extra draws, so their seeded results can differ from
|
|
59
|
+
* sampling their collected values.
|
|
60
|
+
* @param collection The collection to draw from.
|
|
61
|
+
* @param options `random`, the source of randomness.
|
|
62
|
+
* @returns The value drawn.
|
|
63
|
+
* @throws {TypeError} when `random` is not a function or returns a value that is not a number.
|
|
64
|
+
* @throws {RangeError} when `random` returns a number outside `[0, 1)`.
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* sample([1, 2, 3]) // 1, 2 or 3
|
|
68
|
+
* sample({ a: 1, b: 2 }) // 1 or 2
|
|
69
|
+
* ```
|
|
18
70
|
*/
|
|
19
|
-
export declare function
|
|
71
|
+
export declare function sample<C extends Collection>(collection: C, options?: RandomOptions): CollectionValue<C> | undefined;
|
|
20
72
|
/**
|
|
21
|
-
* Returns
|
|
22
|
-
* @
|
|
23
|
-
*
|
|
73
|
+
* Returns `n` values of a collection at distinct positions, in random order, or every value when
|
|
74
|
+
* it has fewer than `n`. Sampling follows {@link sample}, including its collection shapes and
|
|
75
|
+
* sparse-array behavior. Full samples, and samples of at least five values covering at least half
|
|
76
|
+
* an array or typed array, copy its values before drawing. Smaller partial samples read only
|
|
77
|
+
* selected positions unless a missing position triggers a full scan. An `n` of 0 reads no values.
|
|
78
|
+
* @param collection The collection to draw from.
|
|
79
|
+
* @param n How many values to draw.
|
|
80
|
+
* @param options `random`, the source of randomness.
|
|
81
|
+
* @returns The values drawn.
|
|
82
|
+
* @throws {TypeError} when `n` is not a number, `random` is not a function or it returns a value
|
|
83
|
+
* that is not a number.
|
|
84
|
+
* @throws {RangeError} when `n` is not a non-negative integer or `random` returns a number outside
|
|
85
|
+
* `[0, 1)`.
|
|
86
|
+
* @example
|
|
87
|
+
* ```ts
|
|
88
|
+
* sampleSize([1, 2, 3], 2) // two of them, such as [3, 1]
|
|
89
|
+
* sampleSize([1, 2, 3], 4) // all three, shuffled
|
|
90
|
+
* ```
|
|
24
91
|
*/
|
|
25
|
-
export declare function
|
|
92
|
+
export declare function sampleSize<C extends Collection>(collection: C, n: number, options?: RandomOptions): CollectionValue<C>[];
|
|
26
93
|
/**
|
|
27
|
-
* Returns a
|
|
28
|
-
* @
|
|
29
|
-
* @param
|
|
30
|
-
* @
|
|
31
|
-
* @
|
|
94
|
+
* Returns the values of a collection in random order, with a Fisher-Yates shuffle. It never
|
|
95
|
+
* changes `collection`; collections follow the shapes of {@link sample}.
|
|
96
|
+
* @param collection The collection to shuffle.
|
|
97
|
+
* @param options `random`, the source of randomness.
|
|
98
|
+
* @returns A new array of the values.
|
|
99
|
+
* @throws {TypeError} when `random` is not a function or returns a value that is not a number.
|
|
100
|
+
* @throws {RangeError} when `random` returns a number outside `[0, 1)`.
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* shuffle([1, 2, 3, 4]) // such as [3, 1, 4, 2]
|
|
104
|
+
* ```
|
|
32
105
|
*/
|
|
33
|
-
export declare function
|
|
34
|
-
/**
|
|
35
|
-
* Shuffles a collection elements in-place. Uses the Fisher-Yates algorithm for uniform shuffling. If collection is an Object it returns shuffled `Object.values()`.
|
|
36
|
-
*
|
|
37
|
-
* @param {Array} arr
|
|
38
|
-
* @param {number} size
|
|
39
|
-
* @returns The shuffled array.
|
|
40
|
-
* @template T
|
|
41
|
-
*/
|
|
42
|
-
export declare function shuffle<T>(arr: T[], size?: number): T[];
|
|
106
|
+
export declare function shuffle<C extends Collection>(collection: C, options?: RandomOptions): CollectionValue<C>[];
|
package/dist/random/index.js
CHANGED
|
@@ -1,72 +1,234 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
2
|
+
* Random numbers and draws: `random`, `randomInt`, `sample`, `sampleSize` and `shuffle`. Every
|
|
3
|
+
* function uses `Math.random` unless given `{ random }`, a function that returns numbers in
|
|
4
|
+
* `[0, 1)`. `Math.random` is not cryptographically secure, so do not draw tokens, keys or anything
|
|
5
|
+
* secret with it: use `fns/id` or `crypto.getRandomValues` for those.
|
|
4
6
|
* @module random
|
|
5
7
|
*/
|
|
6
|
-
import {
|
|
8
|
+
import { values } from '../collections/entries.js';
|
|
9
|
+
import { isEnumerable } from '../internal/keys.js';
|
|
10
|
+
import { typedArrayLength } from '../internal/kind.js';
|
|
11
|
+
const TWO_32 = 2 ** 32;
|
|
12
|
+
const TWO_53 = 2 ** 53;
|
|
13
|
+
/** Redraws before accepting that a stubbed source keeps repeating a rejected draw. */
|
|
14
|
+
const MAX_DRAWS = 64;
|
|
15
|
+
function isRandomNumberOptions(x) {
|
|
16
|
+
return typeof x === 'object' && x !== null;
|
|
17
|
+
}
|
|
18
|
+
/** The source `options` names, checked on every draw against the `[0, 1)` contract. */
|
|
19
|
+
function sourceOf(options) {
|
|
20
|
+
const source = options?.random ?? Math.random;
|
|
21
|
+
if (typeof source !== 'function')
|
|
22
|
+
throw new TypeError('random must be a function');
|
|
23
|
+
return () => {
|
|
24
|
+
const r = source();
|
|
25
|
+
if (typeof r !== 'number')
|
|
26
|
+
throw new TypeError('random must return a number');
|
|
27
|
+
if (!(r >= 0 && r < 1))
|
|
28
|
+
throw new RangeError('random must return a number in [0, 1)');
|
|
29
|
+
return r;
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/** The top 32 bits of one draw, which every source with at least 32 bits of precision fills. */
|
|
33
|
+
function draw32(source) {
|
|
34
|
+
return Math.floor(source() * TWO_32);
|
|
35
|
+
}
|
|
36
|
+
/** 53 random bits from two 32-bit chunks, so no bit depends on the precision of the source. */
|
|
37
|
+
function draw53(source) {
|
|
38
|
+
const high21 = Math.floor(draw32(source) / 2 ** 11);
|
|
39
|
+
return high21 * TWO_32 + draw32(source);
|
|
40
|
+
}
|
|
41
|
+
function uniformInt(min, max, source) {
|
|
42
|
+
// A span of up to 2^32 values takes one 32-bit draw, a wider one a 53-bit draw, and a span wider
|
|
43
|
+
// than 2^53 adds a coin flip for the top bit.
|
|
44
|
+
const narrow = max - min < TWO_32;
|
|
45
|
+
const wide = max - min >= TWO_53;
|
|
46
|
+
const range = narrow ? TWO_32 : TWO_53;
|
|
47
|
+
const span = wide ? TWO_53 : max - min + 1;
|
|
48
|
+
const bucket = (range - (range % span)) / span;
|
|
49
|
+
for (let draws = 0; draws < MAX_DRAWS; draws++) {
|
|
50
|
+
const draw = narrow ? draw32(source) : draw53(source);
|
|
51
|
+
const top = wide && source() >= 0.5 ? TWO_53 : 0;
|
|
52
|
+
const value = min + top + (draw - (draw % bucket)) / bucket;
|
|
53
|
+
if (value <= max)
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
return max;
|
|
57
|
+
}
|
|
58
|
+
/** Moves `size` uniformly drawn items to the front of `items` (Fisher-Yates) and keeps those. */
|
|
59
|
+
function drawInPlace(items, size, source) {
|
|
60
|
+
for (let i = 0; i < size && i < items.length - 1; i++) {
|
|
61
|
+
const j = uniformInt(i, items.length - 1, source);
|
|
62
|
+
[items[i], items[j]] = [items[j], items[i]];
|
|
63
|
+
}
|
|
64
|
+
items.length = size;
|
|
65
|
+
return items;
|
|
66
|
+
}
|
|
67
|
+
function indexedLength(collection) {
|
|
68
|
+
if (Array.isArray(collection))
|
|
69
|
+
return collection.length;
|
|
70
|
+
if (typeof collection === 'object' && collection !== null)
|
|
71
|
+
return typedArrayLength(collection);
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
function drawIndices(collection, length, size, source) {
|
|
75
|
+
const indices = [];
|
|
76
|
+
const displaced = new Map();
|
|
77
|
+
for (let i = 0; i < size; i++) {
|
|
78
|
+
const j = i < length - 1 ? uniformInt(i, length - 1, source) : i;
|
|
79
|
+
const index = displaced.get(j) ?? j;
|
|
80
|
+
if (Array.isArray(collection) && !isEnumerable(collection, index)) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
displaced.set(j, displaced.get(i) ?? i);
|
|
84
|
+
indices.push(index);
|
|
85
|
+
}
|
|
86
|
+
return indices;
|
|
87
|
+
}
|
|
7
88
|
/**
|
|
8
|
-
* Returns a random
|
|
9
|
-
*
|
|
10
|
-
* @param
|
|
11
|
-
* @
|
|
89
|
+
* Returns a uniform random integer from `min` to `max`, both included, across any span of safe
|
|
90
|
+
* integers.
|
|
91
|
+
* @param min The lower bound (included).
|
|
92
|
+
* @param max The upper bound (included).
|
|
93
|
+
* @param options `random`, the source of randomness.
|
|
94
|
+
* @returns The integer.
|
|
95
|
+
* @throws {TypeError} when a bound is not a number, `random` is not a function or it returns a
|
|
96
|
+
* value that is not a number.
|
|
97
|
+
* @throws {RangeError} when a bound is not a safe integer, `max < min`, or `random` returns a
|
|
98
|
+
* number outside `[0, 1)`.
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* randomInt(1, 6) // a die roll
|
|
102
|
+
* ```
|
|
12
103
|
*/
|
|
13
|
-
export function
|
|
14
|
-
|
|
15
|
-
|
|
104
|
+
export function randomInt(min, max, options) {
|
|
105
|
+
if (typeof min !== 'number' || typeof max !== 'number') {
|
|
106
|
+
throw new TypeError('min and max must be numbers');
|
|
107
|
+
}
|
|
108
|
+
if (!Number.isSafeInteger(min) || !Number.isSafeInteger(max)) {
|
|
109
|
+
throw new RangeError('min and max must be safe integers');
|
|
110
|
+
}
|
|
111
|
+
if (max < min)
|
|
112
|
+
throw new RangeError('max must be >= min');
|
|
113
|
+
return uniformInt(min, max, sourceOf(options));
|
|
16
114
|
}
|
|
17
115
|
/**
|
|
18
|
-
*
|
|
19
|
-
* @param
|
|
20
|
-
* @param
|
|
21
|
-
* @returns {number}
|
|
116
|
+
* @param first `min`, `max`, or the options.
|
|
117
|
+
* @param second `max`, or the options.
|
|
118
|
+
* @param third The options.
|
|
22
119
|
*/
|
|
23
|
-
export function
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
120
|
+
export function random(first, second, third) {
|
|
121
|
+
const options = [first, second, third].find(isRandomNumberOptions);
|
|
122
|
+
const bounds = [];
|
|
123
|
+
for (const bound of [first, second]) {
|
|
124
|
+
if (bound === undefined || isRandomNumberOptions(bound))
|
|
125
|
+
continue;
|
|
126
|
+
if (typeof bound !== 'number')
|
|
127
|
+
throw new TypeError('min and max must be numbers');
|
|
128
|
+
bounds.push(bound);
|
|
129
|
+
}
|
|
130
|
+
const [min, max] = bounds.length === 2 ? bounds : [0, bounds[0] ?? 1];
|
|
131
|
+
if (!Number.isFinite(min) || !Number.isFinite(max)) {
|
|
132
|
+
throw new RangeError('min and max must be finite');
|
|
133
|
+
}
|
|
134
|
+
if (max < min)
|
|
135
|
+
throw new RangeError('max must be >= min');
|
|
136
|
+
const source = sourceOf(options);
|
|
137
|
+
if (!options?.float && Number.isSafeInteger(min) && Number.isSafeInteger(max)) {
|
|
138
|
+
return uniformInt(min, max, source);
|
|
139
|
+
}
|
|
140
|
+
const r = source();
|
|
141
|
+
const value = min * (1 - r) + max * r;
|
|
142
|
+
return value >= min && value < max ? value : min;
|
|
27
143
|
}
|
|
28
144
|
/**
|
|
29
|
-
* Returns
|
|
30
|
-
*
|
|
31
|
-
*
|
|
145
|
+
* Returns a random value of a collection, or `undefined` when it has none. Collections follow the
|
|
146
|
+
* fns/collection shapes: an object gives its own enumerable values, an array its elements (holes
|
|
147
|
+
* skipped), a string its code points, a `Map` or `Set` its values, and any other iterable its
|
|
148
|
+
* items. Arrays and typed arrays read only selected positions unless an array hole triggers a
|
|
149
|
+
* full scan. Sparse arrays may consume extra draws, so their seeded results can differ from
|
|
150
|
+
* sampling their collected values.
|
|
151
|
+
* @param collection The collection to draw from.
|
|
152
|
+
* @param options `random`, the source of randomness.
|
|
153
|
+
* @returns The value drawn.
|
|
154
|
+
* @throws {TypeError} when `random` is not a function or returns a value that is not a number.
|
|
155
|
+
* @throws {RangeError} when `random` returns a number outside `[0, 1)`.
|
|
156
|
+
* @example
|
|
157
|
+
* ```ts
|
|
158
|
+
* sample([1, 2, 3]) // 1, 2 or 3
|
|
159
|
+
* sample({ a: 1, b: 2 }) // 1 or 2
|
|
160
|
+
* ```
|
|
32
161
|
*/
|
|
33
|
-
export function
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
162
|
+
export function sample(collection, options) {
|
|
163
|
+
const source = sourceOf(options);
|
|
164
|
+
const length = indexedLength(collection);
|
|
165
|
+
if (length !== undefined) {
|
|
166
|
+
if (length === 0)
|
|
167
|
+
return undefined;
|
|
168
|
+
const index = uniformInt(0, length - 1, source);
|
|
169
|
+
if (!Array.isArray(collection) || isEnumerable(collection, index)) {
|
|
170
|
+
return collection[index];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
const items = values(collection);
|
|
174
|
+
if (items.length === 0)
|
|
175
|
+
return undefined;
|
|
176
|
+
return items[uniformInt(0, items.length - 1, source)];
|
|
37
177
|
}
|
|
38
178
|
/**
|
|
39
|
-
* Returns a
|
|
40
|
-
* @
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
179
|
+
* Returns `n` values of a collection at distinct positions, in random order, or every value when
|
|
180
|
+
* it has fewer than `n`. Sampling follows {@link sample}, including its collection shapes and
|
|
181
|
+
* sparse-array behavior. Full samples, and samples of at least five values covering at least half
|
|
182
|
+
* an array or typed array, copy its values before drawing. Smaller partial samples read only
|
|
183
|
+
* selected positions unless a missing position triggers a full scan. An `n` of 0 reads no values.
|
|
184
|
+
* @param collection The collection to draw from.
|
|
185
|
+
* @param n How many values to draw.
|
|
186
|
+
* @param options `random`, the source of randomness.
|
|
187
|
+
* @returns The values drawn.
|
|
188
|
+
* @throws {TypeError} when `n` is not a number, `random` is not a function or it returns a value
|
|
189
|
+
* that is not a number.
|
|
190
|
+
* @throws {RangeError} when `n` is not a non-negative integer or `random` returns a number outside
|
|
191
|
+
* `[0, 1)`.
|
|
192
|
+
* @example
|
|
193
|
+
* ```ts
|
|
194
|
+
* sampleSize([1, 2, 3], 2) // two of them, such as [3, 1]
|
|
195
|
+
* sampleSize([1, 2, 3], 4) // all three, shuffled
|
|
196
|
+
* ```
|
|
44
197
|
*/
|
|
45
|
-
export function
|
|
46
|
-
if (
|
|
198
|
+
export function sampleSize(collection, n, options) {
|
|
199
|
+
if (typeof n !== 'number')
|
|
200
|
+
throw new TypeError('n must be a number');
|
|
201
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
202
|
+
throw new RangeError('n must be a non-negative integer');
|
|
203
|
+
const source = sourceOf(options);
|
|
204
|
+
if (n === 0)
|
|
47
205
|
return [];
|
|
48
|
-
|
|
206
|
+
const length = indexedLength(collection);
|
|
207
|
+
if (length !== undefined && n < length && (n < 5 || n < length / 2)) {
|
|
208
|
+
const indices = drawIndices(collection, length, Math.min(n, length), source);
|
|
209
|
+
if (indices !== undefined) {
|
|
210
|
+
const items = collection;
|
|
211
|
+
return indices.map((index) => items[index]);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
const items = values(collection);
|
|
215
|
+
return drawInPlace(items, Math.min(n, items.length), source);
|
|
49
216
|
}
|
|
50
217
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* @param
|
|
54
|
-
* @param
|
|
55
|
-
* @returns
|
|
56
|
-
* @
|
|
218
|
+
* Returns the values of a collection in random order, with a Fisher-Yates shuffle. It never
|
|
219
|
+
* changes `collection`; collections follow the shapes of {@link sample}.
|
|
220
|
+
* @param collection The collection to shuffle.
|
|
221
|
+
* @param options `random`, the source of randomness.
|
|
222
|
+
* @returns A new array of the values.
|
|
223
|
+
* @throws {TypeError} when `random` is not a function or returns a value that is not a number.
|
|
224
|
+
* @throws {RangeError} when `random` returns a number outside `[0, 1)`.
|
|
225
|
+
* @example
|
|
226
|
+
* ```ts
|
|
227
|
+
* shuffle([1, 2, 3, 4]) // such as [3, 1, 4, 2]
|
|
228
|
+
* ```
|
|
57
229
|
*/
|
|
58
|
-
export function shuffle(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return arr;
|
|
63
|
-
if (size == null || size >= arr.length)
|
|
64
|
-
size = arr.length - 1;
|
|
65
|
-
for (let i = 0; i <= size; i++) {
|
|
66
|
-
const j = randomInt(i, size);
|
|
67
|
-
const temp = arr[j];
|
|
68
|
-
arr[j] = arr[i];
|
|
69
|
-
arr[i] = temp;
|
|
70
|
-
}
|
|
71
|
-
return arr;
|
|
230
|
+
export function shuffle(collection, options) {
|
|
231
|
+
const source = sourceOf(options);
|
|
232
|
+
const items = values(collection);
|
|
233
|
+
return drawInPlace(items, items.length, source);
|
|
72
234
|
}
|