Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@thi.ng/arrays

Package Overview
Dependencies
Maintainers
1
Versions
190
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@thi.ng/arrays - npm Package Compare versions

Comparing version 2.7.7 to 2.7.8

32

arg-sort.js
import { compare } from "@thi.ng/compare/compare";
import { fillRange } from "./fill-range.js";
import { sortByCachedKey } from "./sort-cached.js";
/**
* Returns a new array of numeric indices in same order as sorted values of
* `src` using given (optional) comparator (default: thi.ng/compare). The `src`
* array will remain unmodified.
*
* @remarks
* Also see {@link swizzle} to read an array in custom order.
*
* @example
* ```ts
* const src = ["a", "c", "d", "b"];
*
* argSort(src)
* // [ 0, 3, 1, 2 ]
*
* // src[0] => "a"
* // src[3] => "b"
* // src[1] => "c"
* // src[2] => "d"
*
* swizzle(argSort(src))(src)
* // [ 'a', 'b', 'c', 'd' ]
* ```
*
* @param src -
* @param cmp -
*/
export const argSort = (src, cmp = compare) => sortByCachedKey(fillRange(new Array(src.length)), src.slice(), cmp);
const argSort = (src, cmp = compare) => sortByCachedKey(fillRange(new Array(src.length)), src.slice(), cmp);
export {
argSort
};

54

argmin.js

@@ -1,42 +0,16 @@

/**
* Takes an array of numbers and returns the index of the item which is
* considered the minimum value according to the given initial `min` value
* (default: ∞) and predicate (both optional). Returns -1 if `items` is empty.
*
* @remarks
* See {@link argMax}.
*
* @example
* ```ts
* argMin([42, 11, 66, 23])
* // 1
*
* // same as argmax() with defaults
* argMin([42, 11, 66, 23], -Infinity, (a, b) => a > b)
* // 2
* ```
*
* @param buf
* @param min
* @param pred
*/
export const argMin = (buf, min = Infinity, pred = (a, b) => a < b) => {
let id = -1;
for (let i = 0, n = buf.length; i < n; i++) {
const x = buf[i];
if (pred(x, min)) {
min = x;
id = i;
}
const argMin = (buf, min = Infinity, pred = (a, b) => a < b) => {
let id = -1;
for (let i = 0, n = buf.length; i < n; i++) {
const x = buf[i];
if (pred(x, min)) {
min = x;
id = i;
}
return id;
}
return id;
};
/**
* Similar to {@link argMin}, but selects index of maximum item. Returns -1 if
* `items` is empty.
*
* @param items
* @param min
* @param pred
*/
export const argMax = (items, min = -Infinity, pred = (a, b) => a > b) => argMin(items, min, pred);
const argMax = (items, min = -Infinity, pred = (a, b) => a > b) => argMin(items, min, pred);
export {
argMax,
argMin
};
import { compare } from "@thi.ng/compare/compare";
import { compareNumAsc } from "@thi.ng/compare/numeric";
/**
* Returns the supposed index of `x` in pre-sorted array-like collection `buf`.
*
* @remarks
* If `x` can't be found, returns `-index-1`, representing the negative of the
* index, were `x` to be inserted into `buf`. E.g if the return value is -3, `x`
* would appear/insert at index 2.
*
* The optional `key` function is used to obtain the actual sort value of `x`
* and each array item (default: identity).
*
* The optional `cmp` comparator (default:
* [`compare()`](https://docs.thi.ng/umbrella/compare/functions/compare.html))
* is then used to identify the index of `x`. The sort order of `buf` MUST be
* compatible with that of `cmp`.
*
* @example
* ```ts
* binarySearch([2, 4, 6], 5);
* // -3
* ```
*
* @param buf - array
* @param x - search value
* @param key - key function
* @param cmp - comparator
* @param low - min index
* @param high - max index
*/
export const binarySearch = (buf, x, key = (x) => x, cmp = compare, low = 0, high = buf.length - 1) => {
const kx = key(x);
while (low <= high) {
const mid = (low + high) >>> 1;
const c = cmp(key(buf[mid]), kx);
if (c < 0) {
low = mid + 1;
}
else if (c > 0) {
high = mid - 1;
}
else {
return mid;
}
const binarySearch = (buf, x, key = (x2) => x2, cmp = compare, low = 0, high = buf.length - 1) => {
const kx = key(x);
while (low <= high) {
const mid = low + high >>> 1;
const c = cmp(key(buf[mid]), kx);
if (c < 0) {
low = mid + 1;
} else if (c > 0) {
high = mid - 1;
} else {
return mid;
}
return -low - 1;
}
return -low - 1;
};
/**
* Similar to {@link binarySearch}, but optimized for numeric arrays and
* supporting custom comparators (default:
* [`compareNumAsc()`](https://docs.thi.ng/umbrella/compare/functions/compareNumAsc.html)).
*
* @param buf - array
* @param x - search value
* @param cmp - comparator
* @param low - min index
* @param high - max index
*/
export const binarySearchNumeric = (buf, x, cmp = compareNumAsc, low = 0, high = buf.length - 1) => {
while (low <= high) {
const mid = (low + high) >>> 1;
const c = cmp(buf[mid], x);
if (c < 0) {
low = mid + 1;
}
else if (c > 0) {
high = mid - 1;
}
else {
return mid;
}
const binarySearchNumeric = (buf, x, cmp = compareNumAsc, low = 0, high = buf.length - 1) => {
while (low <= high) {
const mid = low + high >>> 1;
const c = cmp(buf[mid], x);
if (c < 0) {
low = mid + 1;
} else if (c > 0) {
high = mid - 1;
} else {
return mid;
}
return -low - 1;
}
return -low - 1;
};
export const binarySearch2 = (buf, x) => {
let idx = buf[1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
const binarySearch2 = (buf, x) => {
let idx = buf[1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
* Non-recursive, optimized binary search for fixed size numeric arrays of 4
* values. Returns index of `x` or `-index-1` if not found.
*
* @param buf -
* @param x -
*/
export const binarySearch4 = (buf, x) => {
let idx = buf[2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
const binarySearch4 = (buf, x) => {
let idx = buf[2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
* Non-recursive, optimized binary search for fixed size numeric arrays of 8
* values. Returns index of `x` or `-index-1` if not found.
*
* @param buf -
* @param x -
*/
export const binarySearch8 = (buf, x) => {
let idx = buf[4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
const binarySearch8 = (buf, x) => {
let idx = buf[4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
* Non-recursive, optimized binary search for fixed size numeric arrays of 16
* values. Returns index of `x` or `-index-1` if not found.
*
* @param buf -
* @param x -
*/
export const binarySearch16 = (buf, x) => {
let idx = buf[8] <= x ? 8 : 0;
idx |= buf[idx + 4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
const binarySearch16 = (buf, x) => {
let idx = buf[8] <= x ? 8 : 0;
idx |= buf[idx + 4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
* Non-recursive, optimized binary search for fixed size numeric arrays of 32
* values. Returns index of `x` or `-index-1` if not found.
*
* @param buf -
* @param x -
*/
export const binarySearch32 = (buf, x) => {
let idx = buf[16] <= x ? 16 : 0;
idx |= buf[idx + 4] <= x ? 8 : 0;
idx |= buf[idx + 4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
const binarySearch32 = (buf, x) => {
let idx = buf[16] <= x ? 16 : 0;
idx |= buf[idx + 4] <= x ? 8 : 0;
idx |= buf[idx + 4] <= x ? 4 : 0;
idx |= buf[idx + 2] <= x ? 2 : 0;
idx |= buf[idx + 1] <= x ? 1 : 0;
return buf[idx] === x ? idx : buf[0] < x ? -idx - 2 : -1;
};
/**
* {@link binarySearch} result index classifier for predecessor queries.
* Returns index of last item less than search value or -1 if no such
* values exist.
*
* @example
* ```ts
* bsLT(binarySearch([10, 20, 30, 40], 25))
* // 1
* ```
*
* @param i - binarySearch result index
*/
export const bsLT = (i) => (i < 0 ? -i - 2 : i - 1);
/**
* Similar to {@link bsLT}, but for less-than-equals queries.
*
* @param i - binarySearch result index
*/
export const bsLE = (i) => (i < 0 ? -i - 2 : i);
/**
* {@link binarySearch} result index classifier for successor queries.
* Returns index of first item greater than search value or -1 if no
* such values exist.
*
* @example
* ```ts
* src = [10, 20, 30, 40];
*
* bsGT(binarySearch(src, 25), src.length)
* // 2
*
* bsGT(binarySearch(src, 40), src.length)
* // -1
* ```
*
* @param i - binarySearch result index
* @param n - array length
*/
export const bsGT = (i, n) => ((i = i < 0 ? -i - 1 : i + 1), i < n ? i : -1);
/**
* Similar to {@link bsGT}, but for greater-than-equals queries.
*
* @param i - binarySearch result index
* @param n - array length
*/
export const bsGE = (i, n) => ((i = i < 0 ? -i - 1 : i), i < n ? i : -1);
/**
* {@link binarySearch} result index classifier for equals queries.
* Merely syntax sugar, casting any non-found result indices to -1.
*
* @param i - binarySearch result index
*/
export const bsEQ = (i) => (i < 0 ? -1 : i);
const bsLT = (i) => i < 0 ? -i - 2 : i - 1;
const bsLE = (i) => i < 0 ? -i - 2 : i;
const bsGT = (i, n) => (i = i < 0 ? -i - 1 : i + 1, i < n ? i : -1);
const bsGE = (i, n) => (i = i < 0 ? -i - 1 : i, i < n ? i : -1);
const bsEQ = (i) => i < 0 ? -1 : i;
export {
binarySearch,
binarySearch16,
binarySearch2,
binarySearch32,
binarySearch4,
binarySearch8,
binarySearchNumeric,
bsEQ,
bsGE,
bsGT,
bsLE,
bsLT
};

@@ -1,23 +0,12 @@

/**
* Splits array at given index (default: floor(src.length/2)) and returns tuple of [lhs, rhs].
*
* @param src -
* @param i -
*/
export const bisect = (src, i = src.length >>> 1) => [
src.slice(0, i),
src.slice(i),
const bisect = (src, i = src.length >>> 1) => [
src.slice(0, i),
src.slice(i)
];
/**
* Similar to {@link bisect}, but first finds split index via provided
* predicate. The item for which the predicate first returns a truthy result,
* will be the first item in the RHS array. If the predicate never succeeds, the
* function returns `[src, []]`, i.e. all items will remain in the LHS.
*
* @param src -
* @param pred -
*/
export const bisectWith = (src, pred) => {
const i = src.findIndex(pred);
return i >= 0 ? bisect(src, i) : [src, []];
const bisectWith = (src, pred) => {
const i = src.findIndex(pred);
return i >= 0 ? bisect(src, i) : [src, []];
};
export {
bisect,
bisectWith
};

@@ -1,36 +0,39 @@

export function blit1d(dest, x, src, mask) {
const [sx, sw, dx, dw] = __clip(0, src.length, x, dest.length);
if (sw < 1 || dx >= dw)
return dest;
for (let i = 0; i < sw; i++) {
const val = src[sx + i];
val !== mask && (dest[dx + i] = val);
}
function blit1d(dest, x, src, mask) {
const [sx, sw, dx, dw] = __clip(0, src.length, x, dest.length);
if (sw < 1 || dx >= dw)
return dest;
for (let i = 0; i < sw; i++) {
const val = src[sx + i];
val !== mask && (dest[dx + i] = val);
}
return dest;
}
export function blit2d(dest, dpos, dsize, src, ssize, mask) {
const [sx, sw, dx, dw] = __clip(0, ssize[0], dpos[0], dsize[0]);
const [sy, sh, dy, dh] = __clip(0, ssize[1], dpos[1], dsize[1]);
if (sw < 1 || sh < 1 || dx >= dw || dy >= dh)
return dest;
const sstride = ssize[0];
const dstride = dsize[0];
for (let y = 0; y < sh; y++) {
for (let x = 0, soff = (sy + y) * sstride + sx, doff = (dy + y) * dstride + dx; x < sw; x++) {
const val = src[soff + x];
val !== mask && (dest[doff + x] = val);
}
function blit2d(dest, dpos, dsize, src, ssize, mask) {
const [sx, sw, dx, dw] = __clip(0, ssize[0], dpos[0], dsize[0]);
const [sy, sh, dy, dh] = __clip(0, ssize[1], dpos[1], dsize[1]);
if (sw < 1 || sh < 1 || dx >= dw || dy >= dh)
return dest;
const sstride = ssize[0];
const dstride = dsize[0];
for (let y = 0; y < sh; y++) {
for (let x = 0, soff = (sy + y) * sstride + sx, doff = (dy + y) * dstride + dx; x < sw; x++) {
const val = src[soff + x];
val !== mask && (dest[doff + x] = val);
}
return dest;
}
return dest;
}
const __clip = (sx, sw, dx, dw) => {
if (dx < 0) {
sx -= dx;
sw += dx;
dx = 0;
}
else if (dx + sw > dw) {
sw = dw - dx;
}
return [sx, sw, dx, dw];
if (dx < 0) {
sx -= dx;
sw += dx;
dx = 0;
} else if (dx + sw > dw) {
sw = dw - dx;
}
return [sx, sw, dx, dw];
};
export {
blit1d,
blit2d
};
# Change Log
- **Last updated**: 2023-12-09T19:12:03Z
- **Last updated**: 2023-12-11T10:07:09Z
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)

@@ -5,0 +5,0 @@

import { equiv as _eq } from "@thi.ng/equiv";
/**
* Returns true if the last items of `buf` are the same items as in `needle`.
*
* @remarks
* This means `buf` should have at least the same length as `needle` for this to
* be true.
*
* By default, uses
* [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) for
* equality checking.
*
* {@link startsWith}
*
* @param buf - array
* @param needle - search values (array)
* @param equiv - equivalence predicate
*/
export const endsWith = (buf, needle, equiv = _eq) => {
let i = buf.length;
let j = needle.length;
if (i < j)
return false;
while ((--i, j-- > 0 && equiv(buf[i], needle[j]))) { }
return j < 0;
const endsWith = (buf, needle, equiv = _eq) => {
let i = buf.length;
let j = needle.length;
if (i < j)
return false;
while (--i, j-- > 0 && equiv(buf[i], needle[j])) {
}
return j < 0;
};
export {
endsWith
};
import { isArray } from "@thi.ng/checks/is-array";
import { isArrayLike } from "@thi.ng/checks/is-arraylike";
import { ensureIterable } from "./ensure-iterable.js";
/**
* Helper function to avoid unnecessary copying if `x` is already an
* array.
*
* @remarks
* First checks if `x` is an array and if so returns it. Else attempts
* to obtain an iterator from `x` and if successful collects it as array
* and returns it. Throws error if `x` isn't iterable.
*
* @param x -
*/
export const ensureArray = (x) => isArray(x) ? x : [...ensureIterable(x)];
/**
* Similar to {@link ensureArray}, but for `ArrayLike` types.
*
* {@link ensureArray}
*
* @param x -
*/
export const ensureArrayLike = (x) => isArrayLike(x) ? x : [...ensureIterable(x)];
const ensureArray = (x) => isArray(x) ? x : [...ensureIterable(x)];
const ensureArrayLike = (x) => isArrayLike(x) ? x : [...ensureIterable(x)];
export {
ensureArray,
ensureArrayLike
};
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
/**
* Attempts to obtain an iterator from `x` and throws error if `x` is
* not iterable.
*
* @param x -
*/
export const ensureIterable = (x) => {
(x == null || !x[Symbol.iterator]) &&
illegalArgs(`value is not iterable: ${x}`);
return x;
const ensureIterable = (x) => {
(x == null || !x[Symbol.iterator]) && illegalArgs(`value is not iterable: ${x}`);
return x;
};
export {
ensureIterable
};

@@ -1,34 +0,13 @@

/**
* Fills given array with values in [start .. end) interval from `index`
* and with optional `step` size.
*
* @remarks
* `start` and `end` default to 0 and array length, `step` defaults to 1
* or -1 (depending on range). Returns array.
*
* @example
* ```ts
* fillRange(new Array(5))
* // [ 0, 1, 2, 3, 4 ]
*
* fillRange(fillRange([], 0, 10, 20, 2), 5, 20, 8, -2)
* // [ 10, 12, 14, 16, 18, 20, 18, 16, 14, 12, 10 ]
* ```
*
* @param buf -
* @param index -
* @param start -
* @param end -
* @param step -
*/
export const fillRange = (buf, index = 0, start = 0, end = buf.length, step = end > start ? 1 : -1) => {
if (step > 0) {
for (; start < end; start += step)
buf[index++] = start;
}
else {
for (; start > end; start += step)
buf[index++] = start;
}
return buf;
const fillRange = (buf, index = 0, start = 0, end = buf.length, step = end > start ? 1 : -1) => {
if (step > 0) {
for (; start < end; start += step)
buf[index++] = start;
} else {
for (; start > end; start += step)
buf[index++] = start;
}
return buf;
};
export {
fillRange
};
import { equiv as _equiv } from "@thi.ng/equiv";
/**
* Similar to `Array.find()`, but uses [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) as
* default predicate.
*
* @param buf - array
* @param x - search value
* @param equiv - equivalence predicate
*/
export const find = (buf, x, equiv = _equiv) => {
const i = findIndex(buf, x, equiv);
return i !== -1 ? buf[i] : undefined;
const find = (buf, x, equiv = _equiv) => {
const i = findIndex(buf, x, equiv);
return i !== -1 ? buf[i] : void 0;
};
/**
* Similar to `Array.findIndex()`, but uses
* [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) as
* default predicate.
*
* @param buf - array
* @param x - search value
* @param equiv - equivalence predicate
*/
export const findIndex = (buf, x, equiv = _equiv) => {
for (let i = buf.length; i-- > 0;) {
if (equiv(x, buf[i]))
return i;
}
return -1;
const findIndex = (buf, x, equiv = _equiv) => {
for (let i = buf.length; i-- > 0; ) {
if (equiv(x, buf[i]))
return i;
}
return -1;
};
export {
find,
findIndex
};
import { compare } from "@thi.ng/compare/compare";
import { swap } from "./swap.js";
/**
* Implementation of the Floyd-Rivest selection algorithm to partially find &
* sort the `k`th smallest elements in given array, according to supplied
* comparator.
*
* @remarks
* `k` is the desired index value, where `buf[k]` is the `(k+1)`th smallest
* element when `left=0` (default).
*
* **IMPORTANT:** Mutates (partially sorts) given array such that all items in
* the `[left, k]` interval are the smallest.
*
* @example
* ```ts
* floydRivest([5, 3, -1, -10, 20, 7, 0, 4, 2], 3);
* // [ -10, 0, -1, 2, 3, 4, 5, 20, 7 ]
* ```
*
* Based on pseudo-code from:
* - https://en.wikipedia.org/wiki/Floyd%E2%80%93Rivest_algorithm
*
* @param buf
* @param k
* @param cmp
* @param left
* @param right
*/
export const floydRivest = (buf, k = 1, cmp = compare, left = 0, right = buf.length - 1) => {
while (right > left) {
// constants 600 & 0.5 are from original paper
if (right - left > 600) {
const n = right - left + 1;
const i = k - left + 1;
const z = Math.log(n);
const s = 0.5 * Math.exp(z * (2 / 3));
const sd = 0.5 * Math.sqrt(z * s * ((n - s) / n)) * Math.sign(i - n / 2);
floydRivest(buf, k, cmp, Math.max(left, (k - (i * s) / n + sd) | 0), Math.min(right, (k + ((n - i) * s) / n + sd) | 0));
}
const t = buf[k];
let i = left;
let j = right;
swap(buf, left, k);
if (cmp(buf[right], t) > 0)
swap(buf, right, left);
while (i < j) {
swap(buf, i, j);
i++;
j--;
while (compare(buf[i], t) < 0)
i++;
while (compare(buf[j], t) > 0)
j--;
}
if (compare(buf[left], t) === 0) {
swap(buf, left, j);
}
else {
j++;
swap(buf, j, right);
}
if (j <= k)
left = j + 1;
if (k <= j)
right = j - 1;
const floydRivest = (buf, k = 1, cmp = compare, left = 0, right = buf.length - 1) => {
while (right > left) {
if (right - left > 600) {
const n = right - left + 1;
const i2 = k - left + 1;
const z = Math.log(n);
const s = 0.5 * Math.exp(z * (2 / 3));
const sd = 0.5 * Math.sqrt(z * s * ((n - s) / n)) * Math.sign(i2 - n / 2);
floydRivest(
buf,
k,
cmp,
Math.max(left, k - i2 * s / n + sd | 0),
Math.min(right, k + (n - i2) * s / n + sd | 0)
);
}
return buf;
const t = buf[k];
let i = left;
let j = right;
swap(buf, left, k);
if (cmp(buf[right], t) > 0)
swap(buf, right, left);
while (i < j) {
swap(buf, i, j);
i++;
j--;
while (compare(buf[i], t) < 0)
i++;
while (compare(buf[j], t) > 0)
j--;
}
if (compare(buf[left], t) === 0) {
swap(buf, left, j);
} else {
j++;
swap(buf, j, right);
}
if (j <= k)
left = j + 1;
if (k <= j)
right = j - 1;
}
return buf;
};
export {
floydRivest
};
import { equiv as _eq } from "@thi.ng/equiv";
/**
* Performs a fuzzy search of `query` in `domain` and returns `true` if
* successful.
*
* @remarks
* The optional `equiv` predicate can be used to customize item equality
* checking. Uses
* [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) by
* default.
*
* Adapted and generalized from: https://github.com/bevacqua/fufuzzyzzysearch
* (MIT licensed)
*
* [`filterFuzzy()`](https://docs.thi.ng/umbrella/transducers/functions/filterFuzzy.html)
*
* @param domain - array
* @param query - search value
* @param equiv - equivalence predicate
*/
export const fuzzyMatch = (domain, query, equiv = _eq) => {
const nd = domain.length;
const nq = query.length;
if (nq > nd) {
return false;
}
if (nq === nd) {
return equiv(query, domain);
}
next: for (let i = 0, j = 0; i < nq; i++) {
const q = query[i];
while (j < nd) {
if (equiv(domain[j++], q)) {
continue next;
}
const fuzzyMatch = (domain, query, equiv = _eq) => {
const nd = domain.length;
const nq = query.length;
if (nq > nd) {
return false;
}
if (nq === nd) {
return equiv(query, domain);
}
next:
for (let i = 0, j = 0; i < nq; i++) {
const q = query[i];
while (j < nd) {
if (equiv(domain[j++], q)) {
continue next;
}
return false;
}
return false;
}
return true;
return true;
};
export {
fuzzyMatch
};

@@ -1,35 +0,12 @@

/**
* Inserts `x` into `buf` at index `i` and ensures that array length doesn't
* grow beyond max `k` items (default: unbounded).
*
* @remarks
* The function will have no effect iff `i<0` or `i>=k` or `k<1`. If
* `buf.length` is larger than `k`, only the index range [i..k) will be
* modified.
*
* In benchmarking with 4, 8, 16, 32, 64 element arrays, this function is
* consistently 7-16x faster than `Array.prototype.copyWithin()` and 1.5-2x
* faster than `Array.prototype.splice()` (for sizes < ~32). See
* `/bench/insert.ts`
*
* @param buf -
* @param x -
* @param i -
* @param k -
*/
export const insert = (buf, x, i, k = Infinity) => i < 0 || i >= k || k < 1 ? buf : insertUnsafe(buf, x, i, k);
/**
* Same as {@link insert} but without any bounds/index checks.
*
* @param buf -
* @param x -
* @param i -
* @param k -
*/
export const insertUnsafe = (buf, x, i, k = Infinity) => {
let j = buf.length < k ? buf.length + 1 : k;
for (; --j > i;)
buf[j] = buf[j - 1];
buf[i] = x;
return buf;
const insert = (buf, x, i, k = Infinity) => i < 0 || i >= k || k < 1 ? buf : insertUnsafe(buf, x, i, k);
const insertUnsafe = (buf, x, i, k = Infinity) => {
let j = buf.length < k ? buf.length + 1 : k;
for (; --j > i; )
buf[j] = buf[j - 1];
buf[i] = x;
return buf;
};
export {
insert,
insertUnsafe
};

@@ -1,16 +0,11 @@

/**
* Appends `max` items (default: all) from `src` iterable to `dest` array.
* Returns `dest`.
*
* @param dest -
* @param src -
* @param max -
*/
export const into = (dest, src, max = Infinity) => {
for (let x of src) {
if (--max < 0)
break;
dest.push(x);
}
return dest;
const into = (dest, src, max = Infinity) => {
for (let x of src) {
if (--max < 0)
break;
dest.push(x);
}
return dest;
};
export {
into
};
import { compare } from "@thi.ng/compare/compare";
/**
* Returns true if the given array and its elements in the selected index range
* (entire array, by default) are in the order defined by the given comparator
* ([`compare()`](https://docs.thi.ng/umbrella/compare/functions/compare.html)
* by default).
*
* @remarks
* Always returns true, if effective index range (or array length) has less than
* two elements. No bounds checking.
*
* @example
* ```ts
* isSorted([3, 2, 1])
* // false
*
* // w/ custom comparator
* isSorted([3, 2, 1], (a, b) => b - a)
* // true
* ```
*
* @param arr - array
* @param cmp - comparator
* @param start - start index
* @param end - end index
*/
export const isSorted = (arr, cmp = compare, start = 0, end = arr.length) => {
let prev = arr[start];
while (++start < end) {
const curr = arr[start];
if (cmp(prev, curr) > 0)
return false;
prev = curr;
}
return true;
const isSorted = (arr, cmp = compare, start = 0, end = arr.length) => {
let prev = arr[start];
while (++start < end) {
const curr = arr[start];
if (cmp(prev, curr) > 0)
return false;
prev = curr;
}
return true;
};
export {
isSorted
};

@@ -1,23 +0,13 @@

/**
* Returns iterator of nullable array w/ optional index range support
* and/or reverse iteration order. The default range covers the entire
* array.
*
* @remarks
* If `start` > `end`, yields values in reverse order. No bounds
* checking is performed.
*
* @param buf - array or null
* @param start - start index
* @param end - end index (excluded)
*/
export function* arrayIterator(buf, start = 0, end) {
if (!buf)
return;
start = start;
end === undefined && (end = buf.length);
const step = start <= end ? 1 : -1;
for (; start !== end; start += step) {
yield buf[start];
}
function* arrayIterator(buf, start = 0, end) {
if (!buf)
return;
start = start;
end === void 0 && (end = buf.length);
const step = start <= end ? 1 : -1;
for (; start !== end; start += step) {
yield buf[start];
}
}
export {
arrayIterator
};
const eqStrict = (a, b) => a === b;
/**
* Computes Levenshtein distance w/ optionally given `maxDist` (for
* early termination, default: ∞) and equality predicate (default:
* `===`). Returns 0 if both `a` and `b` are equal (based on predicate).
* Returns `Infinity` if actual distance > `maxDist`.
*
* @remarks
*
* Based on:
* - https://en.wikipedia.org/wiki/Levenshtein_distance
* - https://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm
* - https://github.com/gustf/js-levenshtein/blob/develop/index.js
*
* @example
* ```ts
* levenshtein([1, 2, 3, 4, 5], [1, 2, 4, 3, 5]);
* // 2
*
* levenshtein(
* [{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
* [{ id: 4 }, { id: 5 }, { id: 3 }, { id: 1 }, { id: 2 }],
* // max dist
* 2,
* // predicate
* (a, b) => a.id === b.id
* )
* // Infinity
* ```
*
* @param a -
* @param b -
* @param maxDist -
* @param equiv -
*/
export const levenshtein = (a, b, maxDist = Infinity, equiv = eqStrict) => {
if (a === b) {
return 0;
const levenshtein = (a, b, maxDist = Infinity, equiv = eqStrict) => {
if (a === b) {
return 0;
}
if (a.length > b.length) {
const tmp = a;
a = b;
b = tmp;
}
let la = a.length;
let lb = b.length;
while (la > 0 && equiv(a[~-la], b[~-lb])) {
la--;
lb--;
}
let offset = 0;
while (offset < la && equiv(a[offset], b[offset])) {
offset++;
}
la -= offset;
lb -= offset;
if (la === 0 || lb < 3) {
return lb;
}
let x = 0;
let y;
let minDist;
let d0;
let d1;
let d2;
let d3;
let dd;
let dy;
let ay;
let bx0;
let bx1;
let bx2;
let bx3;
const _min = (d02, d12, d22, bx, ay2) => {
return d02 < d12 || d22 < d12 ? d02 > d22 ? d22 + 1 : d02 + 1 : equiv(ay2, bx) ? d12 : d12 + 1;
};
const vector = [];
for (y = 0; y < la; y++) {
vector.push(y + 1, a[offset + y]);
}
const len = vector.length - 1;
const lb3 = lb - 3;
for (; x < lb3; ) {
bx0 = b[offset + (d0 = x)];
bx1 = b[offset + (d1 = x + 1)];
bx2 = b[offset + (d2 = x + 2)];
bx3 = b[offset + (d3 = x + 3)];
dd = x += 4;
minDist = Infinity;
for (y = 0; y < len; y += 2) {
dy = vector[y];
ay = vector[y + 1];
d0 = _min(dy, d0, d1, bx0, ay);
d1 = _min(d0, d1, d2, bx1, ay);
d2 = _min(d1, d2, d3, bx2, ay);
dd = _min(d2, d3, dd, bx3, ay);
dd < minDist && (minDist = dd);
vector[y] = dd;
d3 = d2;
d2 = d1;
d1 = d0;
d0 = dy;
}
if (a.length > b.length) {
const tmp = a;
a = b;
b = tmp;
if (minDist > maxDist)
return Infinity;
}
for (; x < lb; ) {
bx0 = b[offset + (d0 = x)];
dd = ++x;
minDist = Infinity;
for (y = 0; y < len; y += 2) {
dy = vector[y];
vector[y] = dd = _min(dy, d0, dd, bx0, vector[y + 1]);
dd < minDist && (minDist = dd);
d0 = dy;
}
let la = a.length;
let lb = b.length;
while (la > 0 && equiv(a[~-la], b[~-lb])) {
la--;
lb--;
}
let offset = 0;
while (offset < la && equiv(a[offset], b[offset])) {
offset++;
}
la -= offset;
lb -= offset;
if (la === 0 || lb < 3) {
return lb;
}
let x = 0;
let y;
let minDist;
let d0;
let d1;
let d2;
let d3;
let dd;
let dy;
let ay;
let bx0;
let bx1;
let bx2;
let bx3;
const _min = (d0, d1, d2, bx, ay) => {
return d0 < d1 || d2 < d1
? d0 > d2
? d2 + 1
: d0 + 1
: equiv(ay, bx)
? d1
: d1 + 1;
};
const vector = [];
for (y = 0; y < la; y++) {
vector.push(y + 1, a[offset + y]);
}
const len = vector.length - 1;
const lb3 = lb - 3;
for (; x < lb3;) {
bx0 = b[offset + (d0 = x)];
bx1 = b[offset + (d1 = x + 1)];
bx2 = b[offset + (d2 = x + 2)];
bx3 = b[offset + (d3 = x + 3)];
dd = x += 4;
minDist = Infinity;
for (y = 0; y < len; y += 2) {
dy = vector[y];
ay = vector[y + 1];
d0 = _min(dy, d0, d1, bx0, ay);
d1 = _min(d0, d1, d2, bx1, ay);
d2 = _min(d1, d2, d3, bx2, ay);
dd = _min(d2, d3, dd, bx3, ay);
dd < minDist && (minDist = dd);
vector[y] = dd;
d3 = d2;
d2 = d1;
d1 = d0;
d0 = dy;
}
if (minDist > maxDist)
return Infinity;
}
for (; x < lb;) {
bx0 = b[offset + (d0 = x)];
dd = ++x;
minDist = Infinity;
for (y = 0; y < len; y += 2) {
dy = vector[y];
vector[y] = dd = _min(dy, d0, dd, bx0, vector[y + 1]);
dd < minDist && (minDist = dd);
d0 = dy;
}
if (minDist > maxDist)
return Infinity;
}
return dd;
if (minDist > maxDist)
return Infinity;
}
return dd;
};
/**
* Normalized version of {@link levenshtein}, i.e. the actual L-dist
* divided by the length of the longest input (or `Infinity` if actual
* distance > `maxDist`).
*
* @param a -
* @param b -
* @param maxDist -
* @param equiv -
*/
export const normalizedLevenshtein = (a, b, maxDist = Infinity, equiv = eqStrict) => {
const n = Math.max(a.length, b.length);
return n > 0 ? levenshtein(a, b, maxDist, equiv) / n : 0;
const normalizedLevenshtein = (a, b, maxDist = Infinity, equiv = eqStrict) => {
const n = Math.max(a.length, b.length);
return n > 0 ? levenshtein(a, b, maxDist, equiv) / n : 0;
};
export {
levenshtein,
normalizedLevenshtein
};
{
"name": "@thi.ng/arrays",
"version": "2.7.7",
"version": "2.7.8",
"description": "Array / Arraylike utilities",

@@ -27,3 +27,5 @@ "type": "module",

"scripts": {
"build": "yarn clean && tsc --declaration",
"build": "yarn build:esbuild && yarn build:decl",
"build:decl": "tsc --declaration --emitDeclarationOnly",
"build:esbuild": "esbuild --format=esm --platform=neutral --target=es2022 --tsconfig=tsconfig.json --outdir=. src/**/*.ts",
"clean": "rimraf --glob '*.js' '*.d.ts' '*.map' doc",

@@ -37,11 +39,12 @@ "doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",

"dependencies": {
"@thi.ng/api": "^8.9.11",
"@thi.ng/checks": "^3.4.11",
"@thi.ng/compare": "^2.2.7",
"@thi.ng/equiv": "^2.1.36",
"@thi.ng/errors": "^2.4.5",
"@thi.ng/random": "^3.6.17"
"@thi.ng/api": "^8.9.12",
"@thi.ng/checks": "^3.4.12",
"@thi.ng/compare": "^2.2.8",
"@thi.ng/equiv": "^2.1.37",
"@thi.ng/errors": "^2.4.6",
"@thi.ng/random": "^3.6.18"
},
"devDependencies": {
"@microsoft/api-extractor": "^7.38.3",
"esbuild": "^0.19.8",
"rimraf": "^5.0.5",

@@ -168,3 +171,3 @@ "tools": "^0.0.1",

},
"gitHead": "25f2ac8ff795a432a930119661b364d4d93b59a0\n"
"gitHead": "5e7bafedfc3d53bc131469a28de31dd8e5b4a3ff\n"
}

@@ -1,12 +0,6 @@

/**
* Returns first element of given array or `undefined` if array is empty.
*
* @param buf - array
*/
export const first = (buf) => buf[0];
/**
* Returns last element of given array or `undefined` if array is empty.
*
* @param buf - array
*/
export const peek = (buf) => buf[buf.length - 1];
const first = (buf) => buf[0];
const peek = (buf) => buf[buf.length - 1];
export {
first,
peek
};
import { compare } from "@thi.ng/compare/compare";
import { swap } from "./swap.js";
export function quickSort(arr, _cmp = compare, _swap = swap, start = 0, end = arr.length - 1) {
if (start < end) {
const pivot = arr[start + ((end - start) >> 1)];
let s = start - 1;
let e = end + 1;
while (true) {
do {
s++;
} while (_cmp(arr[s], pivot) < 0);
do {
e--;
} while (_cmp(arr[e], pivot) > 0);
if (s >= e)
break;
_swap(arr, s, e);
}
quickSort(arr, _cmp, _swap, start, e);
quickSort(arr, _cmp, _swap, e + 1, end);
function quickSort(arr, _cmp = compare, _swap = swap, start = 0, end = arr.length - 1) {
if (start < end) {
const pivot = arr[start + (end - start >> 1)];
let s = start - 1;
let e = end + 1;
while (true) {
do {
s++;
} while (_cmp(arr[s], pivot) < 0);
do {
e--;
} while (_cmp(arr[e], pivot) > 0);
if (s >= e)
break;
_swap(arr, s, e);
}
return arr;
quickSort(arr, _cmp, _swap, start, e);
quickSort(arr, _cmp, _swap, e + 1, end);
}
return arr;
}
export {
quickSort
};

@@ -1,45 +0,29 @@

/**
* Rotates array by `num` items. If `num < 0` items are rotated left (towards
* the beginning of the array), otherwise to the right (end). The rotation
* distance will be `num % buf.length`. The function is no-op if the resulting
* distance is zero or `buf` is empty.
*
* @remarks
* Not suitable for typed arrays. Use {@link rotateTyped} for those.
*
* @param buf
* @param num
*/
export const rotate = (buf, num) => {
if (!(num = __distance(buf, num)))
return buf;
if (num < 0) {
buf.push(...buf.splice(0, -num));
}
else {
buf.unshift(...buf.splice(-num));
}
const rotate = (buf, num) => {
if (!(num = __distance(buf, num)))
return buf;
if (num < 0) {
buf.push(...buf.splice(0, -num));
} else {
buf.unshift(...buf.splice(-num));
}
return buf;
};
/**
* Same as {@link rotate}, but for optimized for typed arrays!
*
* @param buf
* @param num
*/
export const rotateTyped = (buf, num) => {
if (!(num = __distance(buf, num)))
return buf;
if (num < 0) {
const tmp = buf.slice(0, -num);
buf.copyWithin(0, -num);
buf.set(tmp, buf.length + num);
}
else if (num > 0) {
const tmp = buf.slice(buf.length - num);
buf.copyWithin(num, 0);
buf.set(tmp, 0);
}
const rotateTyped = (buf, num) => {
if (!(num = __distance(buf, num)))
return buf;
if (num < 0) {
const tmp = buf.slice(0, -num);
buf.copyWithin(0, -num);
buf.set(tmp, buf.length + num);
} else if (num > 0) {
const tmp = buf.slice(buf.length - num);
buf.copyWithin(num, 0);
buf.set(tmp, 0);
}
return buf;
};
const __distance = (buf, num) => buf.length ? (num | 0) % buf.length : 0;
export {
rotate,
rotateTyped
};
import { assert } from "@thi.ng/errors/assert";
import { SYSTEM } from "@thi.ng/random/system";
/**
* Shuffles the items in the given index range of array `buf` using Fisher-yates
* and optional `rnd` PRNG.
*
* @remarks
* If neither `start` / `end` are given, the entire array will be shuffled.
* Mutates original array.
*
* See [`IRandom`](https://docs.thi.ng/umbrella/random/interfaces/IRandom.html)
*
* @param buf - array
* @param n - num items
* @param rnd - PRNG
*/
export const shuffleRange = (buf, start = 0, end = buf.length, rnd = SYSTEM) => {
assert(start >= 0 && end >= start && end <= buf.length, `illegal range ${start}..${end}`);
if (end - start > 1) {
for (let i = end; i-- > start;) {
const a = rnd.minmax(start, i + 1) | 0;
const t = buf[a];
buf[a] = buf[i];
buf[i] = t;
}
const shuffleRange = (buf, start = 0, end = buf.length, rnd = SYSTEM) => {
assert(
start >= 0 && end >= start && end <= buf.length,
`illegal range ${start}..${end}`
);
if (end - start > 1) {
for (let i = end; i-- > start; ) {
const a = rnd.minmax(start, i + 1) | 0;
const t = buf[a];
buf[a] = buf[i];
buf[i] = t;
}
return buf;
}
return buf;
};
/**
* Applies {@link shuffleRange} to the given array. If `n` is given,
* only the first `n` items are shuffled. Mutates original array.
*
* {@link shuffleRange}
*
* @param buf - array
* @param n - num items
* @param rnd - PRNG
*/
export const shuffle = (buf, n = buf.length, rnd = SYSTEM) => shuffleRange(buf, 0, n, rnd);
const shuffle = (buf, n = buf.length, rnd = SYSTEM) => shuffleRange(buf, 0, n, rnd);
export {
shuffle,
shuffleRange
};

@@ -6,34 +6,10 @@ import { isFunction } from "@thi.ng/checks/is-function";

import { multiSwap } from "./swap.js";
/**
* Takes a `src` array and `key` array of function to provide the sort key of
* each item. If a function, it will be first applied to pre-compute a new array
* of all sort keys. Then uses {@link quickSort} to sort `src` array, based on
* the ordering of cached keys and the optionally given comparator. Returns
* `src`.
*
* @remarks
* This function is primarily intended for use cases where an array needs to be
* sorted based on the item order of another array, or where sort keys are
* derived from non-trivial computations and need to be cached, rather than be
* re-evaluated multiple times from within a comparator.
*
* @example
* ```ts
* // sort by length in descending order
* sortByCachedKey(["a","bbbb","ccc","dd"], (x) => x.length, (a, b) => b - a);
* // [ 'bbbb', 'ccc', 'dd', 'a' ]
*
* sortByCachedKey(["a", "b", "c", "d"], [3, 2, 1, 0])
* // [ 'd', 'c', 'b', 'a' ]
* ```
*
* @param src -
* @param key -
* @param cmp -
*/
export const sortByCachedKey = (src, key, cmp = compare) => {
const keys = isFunction(key) ? src.map(key) : key;
assert(keys.length === src.length, `keys.length != src.length`);
quickSort(keys, cmp, multiSwap(src));
return src;
const sortByCachedKey = (src, key, cmp = compare) => {
const keys = isFunction(key) ? src.map(key) : key;
assert(keys.length === src.length, `keys.length != src.length`);
quickSort(keys, cmp, multiSwap(src));
return src;
};
export {
sortByCachedKey
};
import { equiv as _eq } from "@thi.ng/equiv";
/**
* Returns true if the first items of `buf` are the same items as in `needle`.
*
* @remarks
* This means `buf` should have at least the same length as `needle` for this to
* be true.
*
* By default, uses
* [`equiv()`](https://docs.thi.ng/umbrella/equiv/functions/equiv.html) for
* equality checking.
*
* {@link endsWith}
*
* @param buf - array
* @param needle - search value
* @param equiv - equivalence predicate
*/
export const startsWith = (buf, needle, equiv = _eq) => {
let i = buf.length;
let j = needle.length;
if (i < j)
return false;
while (-j >= 0 && equiv(buf[j], needle[j])) { }
return j < 0;
const startsWith = (buf, needle, equiv = _eq) => {
let i = buf.length;
let j = needle.length;
if (i < j)
return false;
while (-j >= 0 && equiv(buf[j], needle[j])) {
}
return j < 0;
};
export {
startsWith
};

@@ -1,73 +0,41 @@

/**
* Swaps values at index `x`/`y` in given array.
*
* @param arr - array
* @param x - first index
* @param y - other index
*/
export const swap = (arr, x, y) => {
const t = arr[x];
arr[x] = arr[y];
arr[y] = t;
const swap = (arr, x, y) => {
const t = arr[x];
arr[x] = arr[y];
arr[y] = t;
};
/**
* Higher-order version of {@link swap} for swapping elements in multiple arrays
* at once and hence useful for sorting multiple arrays based on a single
* criteria.
*
* @remarks
* The returned function takes the same args as `swap`, and when called swaps 2
* elements in the array given to that function AND in the arrays given to
* {@link multiSwap} itself. Provides fast routes for up to 3 extra arrays, then
* falls back to a loop-based approach.
*
* {@link quickSort}
*
* @example
* ```ts
* a = [2, 1];
* b = [20, 10];
* c = [40, 30];
*
* ms = multiSwap(b, c);
* ms(a, 0, 1);
*
* // a: [1, 2]
* // b: [10, 20]
* // c: [30, 40]
* ```
*
* @param xs - arrays to swap in later
*/
export const multiSwap = (...xs) => {
const [b, c, d] = xs;
const n = xs.length;
switch (n) {
case 0:
return swap;
case 1:
return (a, x, y) => {
swap(a, x, y);
swap(b, x, y);
};
case 2:
return (a, x, y) => {
swap(a, x, y);
swap(b, x, y);
swap(c, x, y);
};
case 3:
return (a, x, y) => {
swap(a, x, y);
swap(b, x, y);
swap(c, x, y);
swap(d, x, y);
};
default:
return (a, x, y) => {
swap(a, x, y);
for (let i = n; i-- > 0;)
swap(xs[i], x, y);
};
}
const multiSwap = (...xs) => {
const [b, c, d] = xs;
const n = xs.length;
switch (n) {
case 0:
return swap;
case 1:
return (a, x, y) => {
swap(a, x, y);
swap(b, x, y);
};
case 2:
return (a, x, y) => {
swap(a, x, y);
swap(b, x, y);
swap(c, x, y);
};
case 3:
return (a, x, y) => {
swap(a, x, y);
swap(b, x, y);
swap(c, x, y);
swap(d, x, y);
};
default:
return (a, x, y) => {
swap(a, x, y);
for (let i = n; i-- > 0; )
swap(xs[i], x, y);
};
}
};
export {
multiSwap,
swap
};

@@ -1,56 +0,34 @@

/**
* Returns optimized function to immutably select, repeat, reshape and /
* or reorder array / object values in the specified index order.
*
* @remarks
* Fast paths for up to 8 indices are provided, before a loop based
* approach is used.
*
* @example
* ```ts
* swizzle([0, 0, 0])([1, 2, 3, 4]) // [ 1, 1, 1 ]
* swizzle([1, 1, 3, 3])([1, 2, 3, 4]) // [ 2, 2, 4, 4 ]
* swizzle([2, 0])([1, 2, 3]) // [ 3, 1 ]
* ```
*
* @example
* Objects can be used as input to the generated function, but the
* result will always be in array form.
* ```ts
* swizzle(["a", "c", "b"])({a: 1, b: 2, c: 3}) // [ 1, 3, 2 ]
* ```
*
* @param order - indices
*/
export const swizzle = (order) => {
const [a, b, c, d, e, f, g, h] = order;
switch (order.length) {
case 0:
return () => [];
case 1:
return (x) => [x[a]];
case 2:
return (x) => [x[a], x[b]];
case 3:
return (x) => [x[a], x[b], x[c]];
case 4:
return (x) => [x[a], x[b], x[c], x[d]];
case 5:
return (x) => [x[a], x[b], x[c], x[d], x[e]];
case 6:
return (x) => [x[a], x[b], x[c], x[d], x[e], x[f]];
case 7:
return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g]];
case 8:
return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g], x[h]];
default:
return (x) => {
const res = [];
for (let i = order.length; i-- > 0;) {
res[i] = x[order[i]];
}
return res;
};
}
const swizzle = (order) => {
const [a, b, c, d, e, f, g, h] = order;
switch (order.length) {
case 0:
return () => [];
case 1:
return (x) => [x[a]];
case 2:
return (x) => [x[a], x[b]];
case 3:
return (x) => [x[a], x[b], x[c]];
case 4:
return (x) => [x[a], x[b], x[c], x[d]];
case 5:
return (x) => [x[a], x[b], x[c], x[d], x[e]];
case 6:
return (x) => [x[a], x[b], x[c], x[d], x[e], x[f]];
case 7:
return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g]];
case 8:
return (x) => [x[a], x[b], x[c], x[d], x[e], x[f], x[g], x[h]];
default:
return (x) => {
const res = [];
for (let i = order.length; i-- > 0; ) {
res[i] = x[order[i]];
}
return res;
};
}
};
export {
swizzle
};

@@ -1,50 +0,18 @@

/**
* Higher order function. Takes an object of threshold values and their target
* values, as well as a default value. Returns a new function which then matches
* a given value against all given thresholds and returns a matching target
* value, of (if none matched), the given default.
*
* @remarks
* The thresholds will be sorted & matched in ascending order using `<=`
* comparison.
*
* @example
* ```ts
* const numColumns = selectThresholdMin({ 480: 1, 640: 2, 960: 3 }, 4);
*
* numColumns(320) // 1
*
* numColumns(481) // 2
*
* numColumns(768) // 3
*
* numColumns(1024) // 4
* ```
*
* @param thresholds
* @param defaultVal
*/
export const selectThresholdMin = (thresholds, defaultVal) => {
const $thresholds = Object.entries(thresholds)
.map(([k, v]) => [+k, v])
.sort((a, b) => a[0] - b[0]);
return (x) => {
const res = $thresholds.find((t) => x <= t[0]);
return res ? res[1] : defaultVal;
};
const selectThresholdMin = (thresholds, defaultVal) => {
const $thresholds = Object.entries(thresholds).map(([k, v]) => [+k, v]).sort((a, b) => a[0] - b[0]);
return (x) => {
const res = $thresholds.find((t) => x <= t[0]);
return res ? res[1] : defaultVal;
};
};
/**
* Similar to {@link selectThresholdMin}, but uses `>=` ordering.
*
* @param thresholds
* @param defaultVal
*/
export const selectThresholdMax = (thresholds, defaultVal) => {
const $thresholds = Object.entries(thresholds)
.map(([k, v]) => [+k, v])
.sort((a, b) => b[0] - a[0]);
return (x) => {
const res = $thresholds.find((t) => x >= t[0]);
return res ? res[1] : defaultVal;
};
const selectThresholdMax = (thresholds, defaultVal) => {
const $thresholds = Object.entries(thresholds).map(([k, v]) => [+k, v]).sort((a, b) => b[0] - a[0]);
return (x) => {
const res = $thresholds.find((t) => x >= t[0]);
return res ? res[1] : defaultVal;
};
};
export {
selectThresholdMax,
selectThresholdMin
};
import { illegalState } from "@thi.ng/errors";
/**
* Takes an object describing a DAG of nodes of type T with keys being node IDs.
* Also takes a function which will be applied to each node and either returns
* an array of node IDs the given node depends on or null if the node has no
* dependencies. Traverses all nodes in the graph (object) and returns an array
* of node IDs in topological dependency order.
*
* @remarks
* An error will be thrown if the graph contains cycles. In this case, the full
* cycle will be part of the error message (see second example below).
*
* @example
* ```ts
* const graph = {
* a: { deps: ["c", "b"] },
* b: {},
* c: { deps: ["d"] },
* d: { deps: ["b"] }
* };
* topoSort(graph, (node) => node.deps);
* // [ "b", "d", "c", "a" ]
*
* // An error will be thrown if the graph contains cycles...
* graph.d.deps.push("a");
*
* topoSort(graph, (node) => node.deps);
* // Uncaught Error: illegal state: dependency cycle: a -> c -> d -> a
* ```
*
* @param nodes
* @param deps
* @returns
*/
export const topoSort = (nodes, deps) => {
const cycles = {};
const topology = [];
const sort = (id, path) => {
if (cycles[id])
illegalState(`dependency cycle: ${path.join(" -> ")}`);
cycles[id] = true;
const nodeDeps = deps(nodes[id]);
if (nodeDeps) {
for (let d of nodeDeps)
sort(d, [...path, d]);
}
cycles[id] = false;
if (!topology.includes(id))
topology.push(id);
};
for (let id in nodes)
sort(id, [id]);
return topology;
const topoSort = (nodes, deps) => {
const cycles = {};
const topology = [];
const sort = (id, path) => {
if (cycles[id])
illegalState(`dependency cycle: ${path.join(" -> ")}`);
cycles[id] = true;
const nodeDeps = deps(nodes[id]);
if (nodeDeps) {
for (let d of nodeDeps)
sort(d, [...path, d]);
}
cycles[id] = false;
if (!topology.includes(id))
topology.push(id);
};
for (let id in nodes)
sort(id, [id]);
return topology;
};
export {
topoSort
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc