UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

218 lines 6.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.splitArrayOn = splitArrayOn; exports.partitionArray = partitionArray; exports.allPermutations = allPermutations; exports.partition = partition; exports.getUniqueCombinationsOfSize = getUniqueCombinationsOfSize; exports.arraySum = arraySum; exports.array2bag = array2bag; exports.arrayEqual = arrayEqual; exports.equidistantSampling = equidistantSampling; exports.cartesianProduct = cartesianProduct; const assert_1 = require("../assert"); /** * Splits the array every time the given predicate fires. * The element the split appears on will not be included! * * @example with this we can split on all empty strings: * ``` * splitArrayOn(['a', '', 'b', '', '', 'c'], elem => elem === '') * // => [['a'], ['b'], [], ['c']] * ``` * @example if the last element satisfies the predicate, this will add an empty array element * ``` * splitArrayOn([1,2,3], elem => true) * // => [[], [], [], []] * ``` */ function splitArrayOn(arr, predicate) { const result = []; let current = []; let fired = false; for (const elem of arr) { if (predicate(elem)) { result.push(current); current = []; fired = true; } else { current.push(elem); } } if (fired || current.length > 0) { result.push(current); } return result; } /** * Returns a tuple of two arrays, where the first one contains all elements for which the predicate returned true, * and the second one contains all elements for which the predicate returned false. */ function partitionArray(arr, predicate) { const left = []; const right = []; for (const elem of arr) { if (predicate(elem)) { left.push(elem); } else { right.push(elem); } } return [left, right]; } /** * Generate all permutations of the given array using Heap's algorithm (with its non-recursive variant). * * @param arr - The array to permute * @see getUniqueCombinationsOfSize */ function* allPermutations(arr) { yield arr.slice(); const c = new Array(arr.length).fill(0); let i = 1; while (i < arr.length) { if (c[i] >= i) { c[i] = 0; ++i; } else { // save the swap to 0 (https://stackoverflow.com/questions/9960908/permutations-in-javascript/37580979#37580979) const k = i % 2 && c[i]; const p = arr[i]; arr[i] = arr[k]; arr[k] = p; ++c[i]; i = 1; yield arr.slice(); } } } function partition(arr, predicate) { const left = []; const right = []; for (const elem of arr) { if (predicate(elem)) { left.push(elem); } else { right.push(elem); } } return [left, right]; } /** * Generate all unique combinations of the array with the given size. * In other words, given `[a,b,c]`, as well as `minSize=2` and `maxSize=2`, this will generate `[a,b]`, `[a,c]` and `[b,c]`, * but not, e.g., `[a,a]` or `[b,a]`. * * If `minSize!=maxSize`, the result is guaranteed to be sorted by size. * * @param array - The array to generate combinations from * @param minSize - The inclusive minimum size of the combinations, must be at least `0` and at most `maxSize` * @param maxSize - The inclusive maximum size of the combinations, must be at least `minSize` and at most `array.length` */ function* getUniqueCombinationsOfSize(array, minSize = 0, maxSize = array.length) { (0, assert_1.guard)(minSize >= 0 && minSize <= maxSize, 'minSize must be at least 0 and at most maxSize'); (0, assert_1.guard)(maxSize >= minSize && maxSize <= array.length, 'maxSize must be at least minSize and at most the length of the array'); if (minSize === maxSize && minSize === 1) { for (const elem of array) { yield [elem]; } return; } function* p(t, i, newArr) { // start yielding if min size is reached if (t.length >= minSize) { // only yield if the array has been modified if (newArr) { yield t; } // stop yielding if inclusive max size is reached if (t.length >= maxSize) { return; } } if (i >= array.length) { return; } yield* p(t.concat(array[i]), i + 1, true); yield* p(t, i + 1, false); } yield* p([], 0, true); } /** * Returns the sum of all elements in the given array */ function arraySum(arr) { let sum = 0; for (const elem of arr) { sum += elem; } return sum; } /** * Converts an array into a bag data-structure (in the form of a map mapping the entries/keys to their counts) */ function array2bag(arr) { const result = new Map(); for (const elem of arr) { result.set(elem, (result.get(elem) ?? 0) + 1); } return result; } function arrayEqual(a, b, cmp = (a, b) => a === b) { if (a === undefined || b === undefined) { return a === b; } if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; i++) { if (!cmp(a[i], b[i])) { return false; } } return true; } /** * Samples elements from a list such that the distance between the sampled elements is as equal as possible. * * If the number of elements to sample is greater or equal to the number of elements in the list, the list is returned as is. * If the number of elements to sample is less than or equal to 0, an empty list is returned. * * @param list - list of elements * @param sampleCount - number of elements to sample * @param rounding - rounding mode to use for the index calculation * @returns - a list of elements equidistantly sampled from the input list */ function equidistantSampling(list, sampleCount, rounding = 'ceil') { if (sampleCount >= list.length) { return list.slice(); } else if (sampleCount <= 0) { return []; } const result = []; const step = list.length / sampleCount; for (let i = 0; i < sampleCount; i++) { const index = rounding === 'floor' ? Math.floor(i * step) : Math.ceil(i * step); result.push(list[index]); } return result; } /** * Returns the cartesian product of the given arrays. * @example * * ```ts * cartesianProduct([1, 2], ['a', 'b', 'c'], [true, false]) * // -> [[1, 'a', true], [1, 'a', false], [1, 'b', true], [1, 'b', false], [1, 'c', true], [1, 'c', false], [2, 'a', true], [2, 'a', false], [2, 'b', true], [2, 'b', false], [2, 'c', true], [2, 'c', false]] * ``` * */ function cartesianProduct(...arrays) { return arrays.reduce((a, b) => a.flatMap(x => b.map(y => x.concat(y))), [[]]); } //# sourceMappingURL=arrays.js.map