{"version":3,"file":"array.cjs","names":["cmp","getSecureRandomIfPossible"],"sources":["../../../src/common/data/array.ts"],"sourcesContent":["/* eslint-disable no-cond-assign */\n\nimport type { NestedArray } from '../types'\nimport { getSecureRandomIfPossible } from './math'\nimport { cmp } from './orderby'\n\n/**\n * Return a new array with duplicate values removed. Maintains first occurrence order.\n * @typeParam T - element type\n * @param arr - input array\n * @returns new array containing unique elements from `arr`\n */\nexport function arrayUnique<T>(arr: T[]): T[] {\n  return arr.filter((n: any, index: any) => arr.indexOf(n) === index)\n}\n\n/**\n * Return elements present in `x` but not in `y`.\n * @typeParam T - element type\n * @param left - left-hand array\n * @param right - array of elements to exclude\n * @returns new array with elements from `left` that are not included in `right`\n */\nexport function arrayMinus<T>(left: T[], right: T[]): T[] {\n  return arrayUnique(left.filter((n: any) => !right.includes(n)))\n}\n\n/**\n * Return the union of multiple arrays (unique elements across all inputs).\n * @typeParam T - element type\n * @param arrays - arrays to union\n * @returns new array with unique elements from all provided arrays\n */\nexport function arrayUnion<T>(...arrays: T[][]): T[] {\n  return arrayUnique(arrays.reduce((acc: T[] = [], value) => acc.concat(value), []))\n}\n\n/** `[1,[2,3]]` becomes `[1,2,3]` */\n/**\n * Flatten nested arrays to a single-level array.\n * Example: `[1, [2, 3]]` becomes `[1, 2, 3]`.\n * @typeParam T - element type\n * @param arrays - one or more nested arrays to flatten\n * @returns flattened array containing all elements\n */\nexport function arrayFlatten<T>(...arrays: NestedArray<T>[]): T[] {\n  return (arrays as any).flat(Number.POSITIVE_INFINITY)\n}\n\n/**\n * Return the intersection of two arrays (elements present in both).\n * @typeParam T - element type\n * @param left - first array\n * @param right - second array\n * @returns new array with elements present in both `left` and `right`\n */\nexport function arrayIntersection<T>(left: T[], right: T[]): T[] {\n  return arrayUnique<T>(left).filter((n: any) => right.includes(n))\n}\n\n/**\n * Return the symmetric difference between two arrays (elements in either array but not both).\n * @typeParam T - element type\n */\nexport function arraySymmetricDifference<T>(left: T[], right: T[]): T[] {\n  return arrayMinus(arrayUnion(left, right), arrayIntersection(left, right))\n  // return arrayUnique(x.filter(n => !y.includes(n)).concat(y.filter(n => !x.includes(n))))\n}\n\n// export function arrayApply<T>(fn:  any, a: T[]): T[] {\n//   return a.reduce(fn, [])\n// }\n\n/**\n * Remove all occurrences of `el` from `arr` in-place and return the mutated array.\n * If `arr` is not an array, returns an empty array.\n * @typeParam T - element type\n * @param arr - array to modify\n * @param el - element to remove\n * @returns the same array instance with `el` removed\n */\nexport function arrayRemoveElement<T>(arr: T[], el: T): T[] {\n  if (arr && Array.isArray(arr)) {\n    let index\n    while ((index = arr.indexOf(el)) !== -1)\n      arr.splice(index, 1)\n    return arr\n  }\n  return []\n}\n\n/** Only have it once in the set */\n/**\n * Ensure `el` exists in `arr`. If not present, push it and return the array.\n * @typeParam T - element type\n * @param arr - target array\n * @param el - element to ensure\n * @returns the same array instance (modified if `el` was added)\n */\nexport function arraySetElement<T>(arr: T[], el: T): T[] {\n  if (!arr.includes(el))\n    arr.push(el)\n  return arr\n}\n\n// via https://stackoverflow.com/a/49587869 and Erwin\n/**\n * Filter an array in-place using `fn` and return the same array instance.\n * This replaces the array contents with the filtered result.\n * @typeParam T - element type\n * @param arr - array to filter in-place\n * @param fn - predicate to determine which elements to keep\n * @returns the same array instance after filtering\n */\nexport function arrayFilterInPlace<T>(arr: T[], fn: (el: T) => boolean): T[] {\n  arr.splice(0, arr.length, ...arr.filter(fn))\n  return arr\n}\n\n// via https://stackoverflow.com/a/49587869 and Erwin\n/**\n * Toggle presence of `el` in `array` in-place: remove if present, add if missing.\n * @typeParam T - element type\n * @param arr - array to modify\n * @param el - element to toggle\n * @returns the same array instance after the toggle\n */\nexport function arrayToggleInPlace<T>(arr: T[], el: T): T[] {\n  const index = arr.findIndex(e => e === el)\n  if (index >= 0)\n    arr.splice(index, 1)\n  else arr.push(el)\n  return arr\n}\n\n/**\n * Empty an array in-place (remove all elements) and return it.\n * @typeParam T - element type\n */\nexport function arrayEmptyInPlace<T>(arr: T[]): T[] {\n  arr.splice(0, arr.length)\n  return arr\n}\n\n/**\n * Replace the contents of `array` in-place with `newContent` and return it.\n * @typeParam T - element type\n * @param arr - target array to overwrite\n * @param newContent - new contents to set\n * @returns the same array instance after replacement\n */\nexport function arraySetArrayInPlace<T>(arr: T[], newContent: T[]): T[] {\n  arr.splice(0, arr.length, ...newContent)\n  return arr\n}\n\n/**\n * Return a sorted copy of the provided iterable or array-like object.\n * @typeParam T - element type\n * @param arr - iterable or array-like input\n * @param compareFn - optional compare function (defaults to `cmp`)\n * @returns a new array sorted according to `compareFn`\n */\nexport function arraySorted<T>(\n  arr: Iterable<T> | ArrayLike<T>,\n  compareFn: ((a: T, b: T) => number) | undefined = cmp,\n): T[] {\n  return Array.from(arr).sort(compareFn)\n}\n\n/**\n * Return a new array with numbers sorted in ascending order.\n * @param arr - array of numbers\n * @returns sorted array of numbers\n */\nexport function arraySortedNumbers(arr: number[]): number[] {\n  return arraySorted(arr, (l: number, r: number) => l - r)\n}\n\n/**\n * Check strict equality of two arrays by length and element-wise === comparison.\n * @typeParam T - element type\n * @param array1 - first array\n * @param array2 - second array\n * @returns `true` if arrays are same length and all elements strictly equal\n */\nexport function arrayIsEqual<T>(array1: T[], array2: T[]): boolean {\n  return (\n    array1.length === array2.length\n    && array1.every((value, index) => value === array2[index])\n  )\n}\n\n/**\n * Shuffle an array in-place using a secure random source if available.\n * Note: uses Array.sort with random comparator which is sufficient for many cases but\n * not perfectly uniform. Returns the same mutated array.\n * @typeParam T - element type\n * @param array - array to shuffle in-place\n * @returns the shuffled array (same instance)\n */\nexport function arrayShuffleInPlace<T>(arr: T[]): T[] {\n  arr.sort(() => (getSecureRandomIfPossible() > 0.5 ? 1 : -1))\n\n  // Alternative https://github.com/sindresorhus/array-shuffle/blob/main/index.js#L8\n  // for (let index = array.length - 1; index > 0; index--) {\n  //   const newIndex = Math.floor(Math.random() * (index + 1));\n  //   [array[index], array[newIndex]] = [array[newIndex], array[index]];\n  // }\n\n  return arr\n}\n\n/**\n * Return a shuffled copy of `array` (original array is not modified).\n * @typeParam T - element type\n * @param array - input array\n * @returns a new shuffled array\n */\nexport function arrayShuffle<T>(arr: T[]): T[] {\n  return arrayShuffleInPlace(Array.from(arr))\n}\n\n/** Randomly shuffle the order of the array's elements. Force to have a different order if array has more than one element. */\n/**\n * Shuffle `array` and ensure the returned order differs from the original when possible.\n * If array length is 0 or 1 it is returned unchanged.\n * @typeParam T - element type\n * @param array - input array\n * @returns a shuffled array that's different from the input when feasible\n */\nexport function arrayShuffleForce<T>(arr: T[]): T[] {\n  while (arr.length > 1) {\n    const copy = Array.from(arr)\n    arrayShuffleInPlace(copy)\n    if (!arrayIsEqual(arr, copy))\n      return copy\n  }\n  return arr\n}\n\n/**\n * Return a random element from `array` using a secure random source if available.\n * @typeParam T - element type\n * @param array - input array (must be non-empty)\n * @returns a randomly selected element\n */\nexport function arrayRandomElement<T>(arr: T[]): T {\n  return arr[Math.floor(getSecureRandomIfPossible() * arr.length)]\n}\n\n/**\n * Return the maximum value from one or more nested arrays.\n * Uses the `>` operator for comparison.\n * @typeParam T - element type (should support `>` comparison)\n * @param arrays - nested arrays to search\n * @returns the maximum value or `undefined` if no elements present\n */\nexport function arrayMax<T>(...arrays: NestedArray<T>[]): T {\n  return arrayFlatten(...arrays).reduce(\n    (acc: T, value: T) => (acc != null ? (value > acc ? value : acc) : value),\n    undefined as T,\n  )\n}\n\n/**\n * Return the minimum value from one or more nested arrays.\n * Uses the `<` operator for comparison.\n * @typeParam T - element type (should support `<` comparison)\n * @param arrays - nested arrays to search\n * @returns the minimum value or `undefined` if no elements present\n */\nexport function arrayMin<T>(...arrays: NestedArray<T>[]): T {\n  return arrayFlatten(...arrays).reduce(\n    (acc: T, value: T) => (acc != null ? (value < acc ? value : acc) : value),\n    undefined as T,\n  )\n}\n\n/**\n * Sum all numbers in one or more nested arrays.\n * @param arrays - nested arrays of numbers\n * @returns the numeric sum (0 for empty input)\n */\nexport function arraySum(...arrays: NestedArray<number>[]): number {\n  return arrayFlatten(...arrays).reduce((acc, value) => acc + value, 0)\n}\n\n/**\n * Compute the average of numbers across one or more nested arrays.\n * @param arrays - nested arrays of numbers\n * @returns arithmetic mean (NaN if there are no elements)\n */\nexport function arrayAvg(...arrays: NestedArray<number>[]): number {\n  const flatArray = arrayFlatten(...arrays)\n  return flatArray.reduce((acc, value) => acc + value, 0) / flatArray.length\n}\n\n/**\n * Split an array into chunks of `chunkLength` (last chunk may be smaller).\n * @typeParam T - element type\n * @param arr - input array\n * @param chunkLength - chunk size (positive integer)\n * @returns array of chunk arrays\n */\nexport function arrayBatches<T>(arr: T[], chunkLength: number): T[][] {\n  const chunks = []\n  let i = 0\n  const n = arr.length\n  while (i < n)\n    chunks.push(arr.slice(i, (i += chunkLength)))\n  return chunks\n}\n\n/**\n * Create an array of given `length` filled with `item` or the result of `item(index)`.\n * If `length` is <= 0 an empty array is returned.\n * @typeParam T - element type\n * @param length - desired length of the array\n * @param item - value to fill or a function producing a value per index\n * @returns newly created array of length `length`\n */\nexport function createArray<T>(\n  length = 0,\n  item?: T | ((index: number) => T), // todo remove optional\n): T[] {\n  if (length <= 0)\n    return []\n  const arr: T[] = Array.from({ length })\n  for (let i = 0; i < length; i++)\n    // @ts-expect-error xxx\n    arr[i] = item instanceof Function ? item(i) : item\n  return arr\n}\n"],"mappings":"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"}