UNPKG

@hgargg-0710/one

Version:

A tiny npm library purposed for providing beautiful solutions to frequent miniature (one-line/one-expression) tasks for various JS datatypes.

228 lines (227 loc) 7.96 kB
import { isArray, isNumberConvertible, isUndefined } from "../type/type.js"; import { ownProperties } from "../object/main.js"; import { constant } from "../functional/constant.js"; import { equals } from "../boolean/boolean.js"; import { difference } from "../number/number.js"; /** * Returns a predicate, purpose of which is to indicate that the argument `x` is a `Tuple`, * with `.length` being precisely `n`. */ export const isTuple = (n) => (x) => isArray(x) && x.length === n; /** * A predicate, purpose of which is to determine that the given item is an array of length 2. */ export const isPair = isTuple(2); /** * A type-only no-op function, purpose of which is to treat the given arguments as an array of respective specific type. */ export const tuple = (...args) => args; /** * A function for creating a copy of the given array without the last `count` elements (by default - 1) */ export const lastOut = (x, count = 1) => x.slice(0, x.length - count); /** * A function for obtaining the last element of the given array. */ export const last = (x) => x[lastIndex(x)]; /** * Sets the value of the last element of the array `x` to be `v`. * @returns `v` */ export const setLast = (x, v) => (x[lastIndex(x)] = v); /** * A function for mutating the given array via setting its` `.length` to `0`. */ export const clear = (x) => (x.length = 0); /** * A function for creating a copy of the array with `values` inserted into it at `index`, and `replaceNum(x)` items skipped. */ export const insertion = (replaceNum) => (x, index, ...values) => x .slice(0, index) .concat(values) .concat(x.slice(index + replaceNum(x))); /** * Same as `insertion(constant(0))`. Creates a copy, which is a result of inserting items at a given index without any removal */ export const insert = insertion(constant(0)); /** * Same as `insertion(constant(1))`. Creates a copy, which is a result of inserting items at a given index, removing only a single item */ export const replace = insertion(constant(1)); /** * Creates a copy of a given array, which is a result of removal of `count` items from the given index (default - a single item); */ export const out = (array, index, count = 1) => array.slice(0, index).concat(array.slice(index + count)); /** * Creates a copy of a given array, with the first `count` items removed (by default - 1) */ export const firstOut = (x, count = 1) => x.slice(count); /** * Gets the first item of the array */ export const first = (x) => x[0]; /** * Calls `f` on `x`, assigning all the own keys on `x`, that are not in `excluded` to `x`. * * Useful for creating "hybrid" arrays from existing objects. */ export const propPreserve = (f, excluded = []) => { const excludedSet = new Set(excluded); return (x) => { const result = f(x); const [keys, values] = ownProperties(x); let i = keys.length; while (i--) { const key = keys[i]; if (!isNumberConvertible(key) && !excludedSet.has(key)) result[key] = values[i]; } return result; }; }; /** * Creates a copy of the given array */ export const copy = (x) => [].concat(x); /** * Creates and returns a new array. Same functionality as `array.map(f)`. * * Better performance for much larger inputs (no engine input size optimizations) */ export function map(array, f) { const mapped = Array(array.length); let i = array.length; while (i--) mapped[i] = f(array[i], i, array); return mapped; } /** * Creates and returns a new array. Same functionality as `array.prop(f)`. * * Better performance for much larger inputs (no engine input size optimizations) */ export function filter(array, prop) { const filtered = []; for (let i = 0; i < array.length; ++i) if (prop(array[i], i, array)) filtered.push(array[i]); return filtered; } /** * Creates and returns a new array. Same functionality as `array.reduce(f, init)`. * * Better performance for much larger inputs (no engine input size optimizations) */ export function reduce(array, f, init) { const initLacking = isUndefined(init); let result = initLacking ? array[0] : init; for (let i = +initLacking; i < array.length; ++i) result = f(result, array[i], i); return result; } /** * Creates and returns a new array. Same functionality as `array.reduceRight(f, init)` * * Better performance for much larger inputs (no engine input size optimizations) */ export function reduceRight(array, f, init) { const initLacking = isUndefined(init); let result = initLacking ? last(array) : init; let i = array.length - +initLacking; while (i--) result = f(result, array[i], i); return result; } /** * Allocates and returns a new empty array. */ export const empty = () => []; /** * Conducts the comparison of two iterables `a` and `b` * by converting them to arrays and using element-by-element `pred(a[i], b[i], i)`. * * For comparison to yield `true`, it is required for both arrays to have the same length. * * `pred` defaults to `(x, y) => x === y` */ export const same = (a, b, pred = equals) => { const [aarr, barr] = [a, b].map((x) => Array.from(x)); return aarr.length === barr.length && aarr.every((x, i) => pred(x, barr[i], i)); }; /** * Creates the array consisting of all the unique items of the given * Iterable, in the order in which they appear */ export const uniqueArr = (x) => Array.from(new Set(x)); /** * Returns either the first truthy element of `x`, or `last(x)` */ export const or = (x) => { for (const curr of x) if (curr) return curr; return last(x); }; /** * Returns either the first falsy element of `x` or `last(x)` */ export const and = (x) => { for (const curr of x) if (!curr) return curr; return last(x); }; /** * Creates a function returning new shallow copies of `array` [useful for factoring-out/remembering information about the array`s contents] */ export const allocator = (array) => () => copy(array); /** * Returns the last index of a given array */ export const lastIndex = (array) => array.length - 1; /** * @returns whether the given array is empty */ export const isEmpty = (array) => !array.length; /** * Recursively applies `array.same(a[i], b[i], i)` for `a[i]` and `b[i]` - arrays, * to the given arrays `a` and `b` (otherwise, applying `pred(a[i], b[i], i)`), * and returns the result. */ export const recursiveSame = (a, b, pred = equals) => a.length === b.length && a.every((ax, i) => isArray(ax) && isArray(b[i]) ? recursiveSame(ax, b[i], pred) : pred(a[i], b[i], i)); /** * Calls `array.sort(order)` with `order` defaulting to `number.difference` */ export const sort = (array, order = difference) => array.sort(order); /** * Creates a new function, which creates a new array of length `n`, indexes of which * defined by the `indexes` array (note: which is pre-ordered), are filled with `values`, * the remaining ones being filled by the values of the `x` array */ export const substitute = (n, indexes) => { const filledIndexes = sort(indexes).filter((x) => x < n); const limIndexes = new Set(filledIndexes); return (values) => { const protoArr = Array(n); for (let i = 0; i < filledIndexes.length; ++i) protoArr[filledIndexes[i]] = values[i]; const restIndexes = Array.from(protoArr.keys().filter((x) => !limIndexes.has(x))); return (x) => { const final = protoArr; for (let i = 0; i < restIndexes.length; ++i) final[restIndexes[i]] = x[i]; return copy(final); }; }; }; /** * Returns the array of keys for the given array `x` */ export const keys = (x) => Array.from(x.keys()); /** * Returns an Array of numbers from `0` to `n - 1` */ export const numbers = (n) => Array(n) .fill(0) .map((_x, i) => i);