@thi.ng/arrays 2.7.7 → 2.7.9

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/quicksort.js CHANGED
@@ -1,23 +1,26 @@
1
1
  import { compare } from "@thi.ng/compare/compare";
2
2
  import { swap } from "./swap.js";
3
- export function quickSort(arr, _cmp = compare, _swap = swap, start = 0, end = arr.length - 1) {
4
- if (start < end) {
5
- const pivot = arr[start + ((end - start) >> 1)];
6
- let s = start - 1;
7
- let e = end + 1;
8
- while (true) {
9
- do {
10
- s++;
11
- } while (_cmp(arr[s], pivot) < 0);
12
- do {
13
- e--;
14
- } while (_cmp(arr[e], pivot) > 0);
15
- if (s >= e)
16
- break;
17
- _swap(arr, s, e);
18
- }
19
- quickSort(arr, _cmp, _swap, start, e);
20
- quickSort(arr, _cmp, _swap, e + 1, end);
3
+ function quickSort(arr, _cmp = compare, _swap = swap, start = 0, end = arr.length - 1) {
4
+ if (start < end) {
5
+ const pivot = arr[start + (end - start >> 1)];
6
+ let s = start - 1;
7
+ let e = end + 1;
8
+ while (true) {
9
+ do {
10
+ s++;
11
+ } while (_cmp(arr[s], pivot) < 0);
12
+ do {
13
+ e--;
14
+ } while (_cmp(arr[e], pivot) > 0);
15
+ if (s >= e)
16
+ break;
17
+ _swap(arr, s, e);
21
18
  }
22
- return arr;
19
+ quickSort(arr, _cmp, _swap, start, e);
20
+ quickSort(arr, _cmp, _swap, e + 1, end);
21
+ }
22
+ return arr;
23
23
  }
24
+ export {
25
+ quickSort
26
+ };
package/rotate.js CHANGED
@@ -1,45 +1,29 @@
1
- /**
2
- * Rotates array by `num` items. If `num < 0` items are rotated left (towards
3
- * the beginning of the array), otherwise to the right (end). The rotation
4
- * distance will be `num % buf.length`. The function is no-op if the resulting
5
- * distance is zero or `buf` is empty.
6
- *
7
- * @remarks
8
- * Not suitable for typed arrays. Use {@link rotateTyped} for those.
9
- *
10
- * @param buf
11
- * @param num
12
- */
13
- export const rotate = (buf, num) => {
14
- if (!(num = __distance(buf, num)))
15
- return buf;
16
- if (num < 0) {
17
- buf.push(...buf.splice(0, -num));
18
- }
19
- else {
20
- buf.unshift(...buf.splice(-num));
21
- }
1
+ const rotate = (buf, num) => {
2
+ if (!(num = __distance(buf, num)))
22
3
  return buf;
4
+ if (num < 0) {
5
+ buf.push(...buf.splice(0, -num));
6
+ } else {
7
+ buf.unshift(...buf.splice(-num));
8
+ }
9
+ return buf;
23
10
  };
24
- /**
25
- * Same as {@link rotate}, but for optimized for typed arrays!
26
- *
27
- * @param buf
28
- * @param num
29
- */
30
- export const rotateTyped = (buf, num) => {
31
- if (!(num = __distance(buf, num)))
32
- return buf;
33
- if (num < 0) {
34
- const tmp = buf.slice(0, -num);
35
- buf.copyWithin(0, -num);
36
- buf.set(tmp, buf.length + num);
37
- }
38
- else if (num > 0) {
39
- const tmp = buf.slice(buf.length - num);
40
- buf.copyWithin(num, 0);
41
- buf.set(tmp, 0);
42
- }
11
+ const rotateTyped = (buf, num) => {
12
+ if (!(num = __distance(buf, num)))
43
13
  return buf;
14
+ if (num < 0) {
15
+ const tmp = buf.slice(0, -num);
16
+ buf.copyWithin(0, -num);
17
+ buf.set(tmp, buf.length + num);
18
+ } else if (num > 0) {
19
+ const tmp = buf.slice(buf.length - num);
20
+ buf.copyWithin(num, 0);
21
+ buf.set(tmp, 0);
22
+ }
23
+ return buf;
44
24
  };
45
25
  const __distance = (buf, num) => buf.length ? (num | 0) % buf.length : 0;
26
+ export {
27
+ rotate,
28
+ rotateTyped
29
+ };
package/shuffle.js CHANGED
@@ -1,39 +1,22 @@
1
1
  import { assert } from "@thi.ng/errors/assert";
2
2
  import { SYSTEM } from "@thi.ng/random/system";
3
- /**
4
- * Shuffles the items in the given index range of array `buf` using Fisher-yates
5
- * and optional `rnd` PRNG.
6
- *
7
- * @remarks
8
- * If neither `start` / `end` are given, the entire array will be shuffled.
9
- * Mutates original array.
10
- *
11
- * See [`IRandom`](https://docs.thi.ng/umbrella/random/interfaces/IRandom.html)
12
- *
13
- * @param buf - array
14
- * @param n - num items
15
- * @param rnd - PRNG
16
- */
17
- export const shuffleRange = (buf, start = 0, end = buf.length, rnd = SYSTEM) => {
18
- assert(start >= 0 && end >= start && end <= buf.length, `illegal range ${start}..${end}`);
19
- if (end - start > 1) {
20
- for (let i = end; i-- > start;) {
21
- const a = rnd.minmax(start, i + 1) | 0;
22
- const t = buf[a];
23
- buf[a] = buf[i];
24
- buf[i] = t;
25
- }
3
+ const shuffleRange = (buf, start = 0, end = buf.length, rnd = SYSTEM) => {
4
+ assert(
5
+ start >= 0 && end >= start && end <= buf.length,
6
+ `illegal range ${start}..${end}`
7
+ );
8
+ if (end - start > 1) {
9
+ for (let i = end; i-- > start; ) {
10
+ const a = rnd.minmax(start, i + 1) | 0;
11
+ const t = buf[a];
12
+ buf[a] = buf[i];
13
+ buf[i] = t;
26
14
  }
27
- return buf;
15
+ }
16
+ return buf;
17
+ };
18
+ const shuffle = (buf, n = buf.length, rnd = SYSTEM) => shuffleRange(buf, 0, n, rnd);
19
+ export {
20
+ shuffle,
21
+ shuffleRange
28
22
  };
29
- /**
30
- * Applies {@link shuffleRange} to the given array. If `n` is given,
31
- * only the first `n` items are shuffled. Mutates original array.
32
- *
33
- * {@link shuffleRange}
34
- *
35
- * @param buf - array
36
- * @param n - num items
37
- * @param rnd - PRNG
38
- */
39
- export const shuffle = (buf, n = buf.length, rnd = SYSTEM) => shuffleRange(buf, 0, n, rnd);
package/sort-cached.js CHANGED
@@ -3,36 +3,12 @@ import { compare } from "@thi.ng/compare/compare";
3
3
  import { assert } from "@thi.ng/errors/assert";
4
4
  import { quickSort } from "./quicksort.js";
5
5
  import { multiSwap } from "./swap.js";
6
- /**
7
- * Takes a `src` array and `key` array of function to provide the sort key of
8
- * each item. If a function, it will be first applied to pre-compute a new array
9
- * of all sort keys. Then uses {@link quickSort} to sort `src` array, based on
10
- * the ordering of cached keys and the optionally given comparator. Returns
11
- * `src`.
12
- *
13
- * @remarks
14
- * This function is primarily intended for use cases where an array needs to be
15
- * sorted based on the item order of another array, or where sort keys are
16
- * derived from non-trivial computations and need to be cached, rather than be
17
- * re-evaluated multiple times from within a comparator.
18
- *
19
- * @example
20
- * ```ts
21
- * // sort by length in descending order
22
- * sortByCachedKey(["a","bbbb","ccc","dd"], (x) => x.length, (a, b) => b - a);
23
- * // [ 'bbbb', 'ccc', 'dd', 'a' ]
24
- *
25
- * sortByCachedKey(["a", "b", "c", "d"], [3, 2, 1, 0])
26
- * // [ 'd', 'c', 'b', 'a' ]
27
- * ```
28
- *
29
- * @param src -
30
- * @param key -
31
- * @param cmp -
32
- */
33
- export const sortByCachedKey = (src, key, cmp = compare) => {
34
- const keys = isFunction(key) ? src.map(key) : key;
35
- assert(keys.length === src.length, `keys.length != src.length`);
36
- quickSort(keys, cmp, multiSwap(src));
37
- return src;
6
+ const sortByCachedKey = (src, key, cmp = compare) => {
7
+ const keys = isFunction(key) ? src.map(key) : key;
8
+ assert(keys.length === src.length, `keys.length != src.length`);
9
+ quickSort(keys, cmp, multiSwap(src));
10
+ return src;
11
+ };
12
+ export {
13
+ sortByCachedKey
38
14
  };
package/starts-with.js CHANGED
@@ -1,26 +1,13 @@
1
1
  import { equiv as _eq } from "@thi.ng/equiv";
2
- /**
3
- * Returns true if the first items of `buf` are the same items as in `needle`.
4
- *
5
- * @remarks
6
- * This means `buf` should have at least the same length as `needle` for this to
7
- * be true.
8
- *
9
- * By default, uses
10
- * [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) for
11
- * equality checking.
12
- *
13
- * {@link endsWith}
14
- *
15
- * @param buf - array
16
- * @param needle - search value
17
- * @param equiv - equivalence predicate
18
- */
19
- export const startsWith = (buf, needle, equiv = _eq) => {
20
- let i = buf.length;
21
- let j = needle.length;
22
- if (i < j)
23
- return false;
24
- while (-j >= 0 && equiv(buf[j], needle[j])) { }
25
- return j < 0;
2
+ const startsWith = (buf, needle, equiv = _eq) => {
3
+ let i = buf.length;
4
+ let j = needle.length;
5
+ if (i < j)
6
+ return false;
7
+ while (-j >= 0 && equiv(buf[j], needle[j])) {
8
+ }
9
+ return j < 0;
10
+ };
11
+ export {
12
+ startsWith
26
13
  };
package/swap.js CHANGED
@@ -1,73 +1,41 @@
1
- /**
2
- * Swaps values at index `x`/`y` in given array.
3
- *
4
- * @param arr - array
5
- * @param x - first index
6
- * @param y - other index
7
- */
8
- export const swap = (arr, x, y) => {
9
- const t = arr[x];
10
- arr[x] = arr[y];
11
- arr[y] = t;
1
+ const swap = (arr, x, y) => {
2
+ const t = arr[x];
3
+ arr[x] = arr[y];
4
+ arr[y] = t;
12
5
  };
13
- /**
14
- * Higher-order version of {@link swap} for swapping elements in multiple arrays
15
- * at once and hence useful for sorting multiple arrays based on a single
16
- * criteria.
17
- *
18
- * @remarks
19
- * The returned function takes the same args as `swap`, and when called swaps 2
20
- * elements in the array given to that function AND in the arrays given to
21
- * {@link multiSwap} itself. Provides fast routes for up to 3 extra arrays, then
22
- * falls back to a loop-based approach.
23
- *
24
- * {@link quickSort}
25
- *
26
- * @example
27
- * ```ts
28
- * a = [2, 1];
29
- * b = [20, 10];
30
- * c = [40, 30];
31
- *
32
- * ms = multiSwap(b, c);
33
- * ms(a, 0, 1);
34
- *
35
- * // a: [1, 2]
36
- * // b: [10, 20]
37
- * // c: [30, 40]
38
- * ```
39
- *
40
- * @param xs - arrays to swap in later
41
- */
42
- export const multiSwap = (...xs) => {
43
- const [b, c, d] = xs;
44
- const n = xs.length;
45
- switch (n) {
46
- case 0:
47
- return swap;
48
- case 1:
49
- return (a, x, y) => {
50
- swap(a, x, y);
51
- swap(b, x, y);
52
- };
53
- case 2:
54
- return (a, x, y) => {
55
- swap(a, x, y);
56
- swap(b, x, y);
57
- swap(c, x, y);
58
- };
59
- case 3:
60
- return (a, x, y) => {
61
- swap(a, x, y);
62
- swap(b, x, y);
63
- swap(c, x, y);
64
- swap(d, x, y);
65
- };
66
- default:
67
- return (a, x, y) => {
68
- swap(a, x, y);
69
- for (let i = n; i-- > 0;)
70
- swap(xs[i], x, y);
71
- };
72
- }
6
+ const multiSwap = (...xs) => {
7
+ const [b, c, d] = xs;
8
+ const n = xs.length;
9
+ switch (n) {
10
+ case 0:
11
+ return swap;
12
+ case 1:
13
+ return (a, x, y) => {
14
+ swap(a, x, y);
15
+ swap(b, x, y);
16
+ };
17
+ case 2:
18
+ return (a, x, y) => {
19
+ swap(a, x, y);
20
+ swap(b, x, y);
21
+ swap(c, x, y);
22
+ };
23
+ case 3:
24
+ return (a, x, y) => {
25
+ swap(a, x, y);
26
+ swap(b, x, y);
27
+ swap(c, x, y);
28
+ swap(d, x, y);
29
+ };
30
+ default:
31
+ return (a, x, y) => {
32
+ swap(a, x, y);
33
+ for (let i = n; i-- > 0; )
34
+ swap(xs[i], x, y);
35
+ };
36
+ }
37
+ };
38
+ export {
39
+ multiSwap,
40
+ swap
73
41
  };
package/swizzle.js CHANGED
@@ -1,56 +1,34 @@
1
- /**
2
- * Returns optimized function to immutably select, repeat, reshape and /
3
- * or reorder array / object values in the specified index order.
4
- *
5
- * @remarks
6
- * Fast paths for up to 8 indices are provided, before a loop based
7
- * approach is used.
8
- *
9
- * @example
10
- * ```ts
11
- * swizzle([0, 0, 0])([1, 2, 3, 4]) // [ 1, 1, 1 ]
12
- * swizzle([1, 1, 3, 3])([1, 2, 3, 4]) // [ 2, 2, 4, 4 ]
13
- * swizzle([2, 0])([1, 2, 3]) // [ 3, 1 ]
14
- * ```
15
- *
16
- * @example
17
- * Objects can be used as input to the generated function, but the
18
- * result will always be in array form.
19
-
20
- * ```ts
21
- * swizzle(["a", "c", "b"])({a: 1, b: 2, c: 3}) // [ 1, 3, 2 ]
22
- * ```
23
- *
24
- * @param order - indices
25
- */
26
- export const swizzle = (order) => {
27
- const [a, b, c, d, e, f, g, h] = order;
28
- switch (order.length) {
29
- case 0:
30
- return () => [];
31
- case 1:
32
- return (x) => [x[a]];
33
- case 2:
34
- return (x) => [x[a], x[b]];
35
- case 3:
36
- return (x) => [x[a], x[b], x[c]];
37
- case 4:
38
- return (x) => [x[a], x[b], x[c], x[d]];
39
- case 5:
40
- return (x) => [x[a], x[b], x[c], x[d], x[e]];
41
- case 6:
42
- return (x) => [x[a], x[b], x[c], x[d], x[e], x[f]];
43
- case 7:
44
- return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g]];
45
- case 8:
46
- return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g], x[h]];
47
- default:
48
- return (x) => {
49
- const res = [];
50
- for (let i = order.length; i-- > 0;) {
51
- res[i] = x[order[i]];
52
- }
53
- return res;
54
- };
55
- }
1
+ const swizzle = (order) => {
2
+ const [a, b, c, d, e, f, g, h] = order;
3
+ switch (order.length) {
4
+ case 0:
5
+ return () => [];
6
+ case 1:
7
+ return (x) => [x[a]];
8
+ case 2:
9
+ return (x) => [x[a], x[b]];
10
+ case 3:
11
+ return (x) => [x[a], x[b], x[c]];
12
+ case 4:
13
+ return (x) => [x[a], x[b], x[c], x[d]];
14
+ case 5:
15
+ return (x) => [x[a], x[b], x[c], x[d], x[e]];
16
+ case 6:
17
+ return (x) => [x[a], x[b], x[c], x[d], x[e], x[f]];
18
+ case 7:
19
+ return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g]];
20
+ case 8:
21
+ return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g], x[h]];
22
+ default:
23
+ return (x) => {
24
+ const res = [];
25
+ for (let i = order.length; i-- > 0; ) {
26
+ res[i] = x[order[i]];
27
+ }
28
+ return res;
29
+ };
30
+ }
31
+ };
32
+ export {
33
+ swizzle
56
34
  };
package/threshold.js CHANGED
@@ -1,50 +1,18 @@
1
- /**
2
- * Higher order function. Takes an object of threshold values and their target
3
- * values, as well as a default value. Returns a new function which then matches
4
- * a given value against all given thresholds and returns a matching target
5
- * value, of (if none matched), the given default.
6
- *
7
- * @remarks
8
- * The thresholds will be sorted & matched in ascending order using `<=`
9
- * comparison.
10
- *
11
- * @example
12
- * ```ts
13
- * const numColumns = selectThresholdMin({ 480: 1, 640: 2, 960: 3 }, 4);
14
- *
15
- * numColumns(320) // 1
16
- *
17
- * numColumns(481) // 2
18
- *
19
- * numColumns(768) // 3
20
- *
21
- * numColumns(1024) // 4
22
- * ```
23
- *
24
- * @param thresholds
25
- * @param defaultVal
26
- */
27
- export const selectThresholdMin = (thresholds, defaultVal) => {
28
- const $thresholds = Object.entries(thresholds)
29
- .map(([k, v]) => [+k, v])
30
- .sort((a, b) => a[0] - b[0]);
31
- return (x) => {
32
- const res = $thresholds.find((t) => x <= t[0]);
33
- return res ? res[1] : defaultVal;
34
- };
1
+ const selectThresholdMin = (thresholds, defaultVal) => {
2
+ const $thresholds = Object.entries(thresholds).map(([k, v]) => [+k, v]).sort((a, b) => a[0] - b[0]);
3
+ return (x) => {
4
+ const res = $thresholds.find((t) => x <= t[0]);
5
+ return res ? res[1] : defaultVal;
6
+ };
35
7
  };
36
- /**
37
- * Similar to {@link selectThresholdMin}, but uses `>=` ordering.
38
- *
39
- * @param thresholds
40
- * @param defaultVal
41
- */
42
- export const selectThresholdMax = (thresholds, defaultVal) => {
43
- const $thresholds = Object.entries(thresholds)
44
- .map(([k, v]) => [+k, v])
45
- .sort((a, b) => b[0] - a[0]);
46
- return (x) => {
47
- const res = $thresholds.find((t) => x >= t[0]);
48
- return res ? res[1] : defaultVal;
49
- };
8
+ const selectThresholdMax = (thresholds, defaultVal) => {
9
+ const $thresholds = Object.entries(thresholds).map(([k, v]) => [+k, v]).sort((a, b) => b[0] - a[0]);
10
+ return (x) => {
11
+ const res = $thresholds.find((t) => x >= t[0]);
12
+ return res ? res[1] : defaultVal;
13
+ };
14
+ };
15
+ export {
16
+ selectThresholdMax,
17
+ selectThresholdMin
50
18
  };
package/topo-sort.js CHANGED
@@ -1,54 +1,24 @@
1
1
  import { illegalState } from "@thi.ng/errors";
2
- /**
3
- * Takes an object describing a DAG of nodes of type T with keys being node IDs.
4
- * Also takes a function which will be applied to each node and either returns
5
- * an array of node IDs the given node depends on or null if the node has no
6
- * dependencies. Traverses all nodes in the graph (object) and returns an array
7
- * of node IDs in topological dependency order.
8
- *
9
- * @remarks
10
- * An error will be thrown if the graph contains cycles. In this case, the full
11
- * cycle will be part of the error message (see second example below).
12
- *
13
- * @example
14
- * ```ts
15
- * const graph = {
16
- * a: { deps: ["c", "b"] },
17
- * b: {},
18
- * c: { deps: ["d"] },
19
- * d: { deps: ["b"] }
20
- * };
21
- * topoSort(graph, (node) => node.deps);
22
- * // [ "b", "d", "c", "a" ]
23
- *
24
- * // An error will be thrown if the graph contains cycles...
25
- * graph.d.deps.push("a");
26
- *
27
- * topoSort(graph, (node) => node.deps);
28
- * // Uncaught Error: illegal state: dependency cycle: a -> c -> d -> a
29
- * ```
30
- *
31
- * @param nodes
32
- * @param deps
33
- * @returns
34
- */
35
- export const topoSort = (nodes, deps) => {
36
- const cycles = {};
37
- const topology = [];
38
- const sort = (id, path) => {
39
- if (cycles[id])
40
- illegalState(`dependency cycle: ${path.join(" -> ")}`);
41
- cycles[id] = true;
42
- const nodeDeps = deps(nodes[id]);
43
- if (nodeDeps) {
44
- for (let d of nodeDeps)
45
- sort(d, [...path, d]);
46
- }
47
- cycles[id] = false;
48
- if (!topology.includes(id))
49
- topology.push(id);
50
- };
51
- for (let id in nodes)
52
- sort(id, [id]);
53
- return topology;
2
+ const topoSort = (nodes, deps) => {
3
+ const cycles = {};
4
+ const topology = [];
5
+ const sort = (id, path) => {
6
+ if (cycles[id])
7
+ illegalState(`dependency cycle: ${path.join(" -> ")}`);
8
+ cycles[id] = true;
9
+ const nodeDeps = deps(nodes[id]);
10
+ if (nodeDeps) {
11
+ for (let d of nodeDeps)
12
+ sort(d, [...path, d]);
13
+ }
14
+ cycles[id] = false;
15
+ if (!topology.includes(id))
16
+ topology.push(id);
17
+ };
18
+ for (let id in nodes)
19
+ sort(id, [id]);
20
+ return topology;
21
+ };
22
+ export {
23
+ topoSort
54
24
  };