UNPKG

@softwareventures/array

Version:

Pure functional array manipulation and traversal

1,206 lines 37.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.map = exports.isArray = exports.copy = void 0; exports.isArrayLike = isArrayLike; exports.coerce = coerce; exports.first = first; exports.tail = tail; exports.push = push; exports.pushFn = pushFn; exports.unshift = unshift; exports.unshiftFn = unshiftFn; exports.initial = initial; exports.last = last; exports.only = only; exports.empty = empty; exports.notEmpty = notEmpty; exports.reverse = reverse; exports.slice = slice; exports.sliceFn = sliceFn; exports.take = take; exports.takeFn = takeFn; exports.drop = drop; exports.dropFn = dropFn; exports.takeWhile = takeWhile; exports.takeWhileFn = takeWhileFn; exports.takeUntil = takeUntil; exports.takeUntilFn = takeUntilFn; exports.dropWhile = dropWhile; exports.dropWhileFn = dropWhileFn; exports.dropUntil = dropUntil; exports.dropUntilFn = dropUntilFn; exports.equal = equal; exports.equalFn = equalFn; exports.notEqual = notEqual; exports.notEqualFn = notEqualFn; exports.prefixMatch = prefixMatch; exports.prefixMatchFn = prefixMatchFn; exports.mapFn = mapFn; exports.filter = filter; exports.filterFn = filterFn; exports.exclude = exclude; exports.excludeFn = excludeFn; exports.excludeNull = excludeNull; exports.excludeFirst = excludeFirst; exports.excludeFirstFn = excludeFirstFn; exports.remove = remove; exports.removeFn = removeFn; exports.removeFirst = removeFirst; exports.removeFirstFn = removeFirstFn; exports.fold = fold; exports.foldFn = foldFn; exports.fold1 = fold1; exports.fold1Fn = fold1Fn; exports.foldRight = foldRight; exports.foldRightFn = foldRightFn; exports.foldRight1 = foldRight1; exports.foldRight1Fn = foldRight1Fn; exports.foldMap = foldMap; exports.foldMapFn = foldMapFn; exports.foldMapRight = foldMapRight; exports.foldMapRightFn = foldMapRightFn; exports.contains = contains; exports.containsFn = containsFn; exports.indexOf = indexOf; exports.indexOfFn = indexOfFn; exports.lastIndexOf = lastIndexOf; exports.lastIndexOfFn = lastIndexOfFn; exports.findIndex = findIndex; exports.findIndexFn = findIndexFn; exports.findLastIndex = findLastIndex; exports.findLastIndexFn = findLastIndexFn; exports.find = find; exports.findFn = findFn; exports.findLast = findLast; exports.findLastFn = findLastFn; exports.maximum = maximum; exports.maximumFn = maximumFn; exports.maximumBy = maximumBy; exports.maximumByFn = maximumByFn; exports.minimum = minimum; exports.minimumFn = minimumFn; exports.minimumBy = minimumBy; exports.minimumByFn = minimumByFn; exports.sum = sum; exports.product = product; exports.average = average; exports.and = and; exports.or = or; exports.any = any; exports.anyFn = anyFn; exports.all = all; exports.allFn = allFn; exports.concat = concat; exports.prepend = prepend; exports.append = append; exports.concatMap = concatMap; exports.concatMapFn = concatMapFn; exports.noneNull = noneNull; exports.scan = scan; exports.scanFn = scanFn; exports.scan1 = scan1; exports.scan1Fn = scan1Fn; exports.scanRight = scanRight; exports.scanRightFn = scanRightFn; exports.scanRight1 = scanRight1; exports.scanRight1Fn = scanRight1Fn; exports.split = split; exports.splitFn = splitFn; exports.partition = partition; exports.partitionFn = partitionFn; exports.partitionWhile = partitionWhile; exports.partitionWhileFn = partitionWhileFn; exports.partitionUntil = partitionUntil; exports.partitionUntilFn = partitionUntilFn; exports.zip = zip; exports.zipFn = zipFn; exports.keyBy = keyBy; exports.keyByFn = keyByFn; exports.keyFirstBy = keyFirstBy; exports.keyFirstByFn = keyFirstByFn; exports.keyLastBy = keyLastBy; exports.keyLastByFn = keyLastByFn; exports.mapKeyBy = mapKeyBy; exports.mapKeyByFn = mapKeyByFn; exports.mapKeyFirstBy = mapKeyFirstBy; exports.mapKeyFirstByFn = mapKeyFirstByFn; exports.mapKeyLastBy = mapKeyLastBy; exports.mapKeyLastByFn = mapKeyLastByFn; exports.group = group; exports.groupFn = groupFn; exports.groupByIdentity = groupByIdentity; exports.groupByIdentityFn = groupByIdentityFn; exports.groupByEquality = groupByEquality; exports.groupByEqualityFn = groupByEqualityFn; exports.groupByOrder = groupByOrder; exports.groupByOrderFn = groupByOrderFn; exports.groupByHash = groupByHash; exports.groupByHashFn = groupByHashFn; exports.groupByEqualityWithHash = groupByEqualityWithHash; exports.groupByEqualityWithHashFn = groupByEqualityWithHashFn; exports.groupByOrderWithHash = groupByOrderWithHash; exports.groupByOrderWithHashFn = groupByOrderWithHashFn; exports.groupAdjacent = groupAdjacent; exports.groupAdjacentFn = groupAdjacentFn; exports.groupAdjacentByIdentity = groupAdjacentByIdentity; exports.groupAdjacentByIdentityFn = groupAdjacentByIdentityFn; exports.groupAdjacentByEquality = groupAdjacentByEquality; exports.groupAdjacentByEqualityFn = groupAdjacentByEqualityFn; exports.groupAdjacentByOrder = groupAdjacentByOrder; exports.groupAdjacentByOrderFn = groupAdjacentByOrderFn; exports.groupAdjacentByHash = groupAdjacentByHash; exports.groupAdjacentByHashFn = groupAdjacentByHashFn; exports.unique = unique; exports.uniqueFn = uniqueFn; exports.uniqueByIdentity = uniqueByIdentity; exports.uniqueByEquality = uniqueByEquality; exports.uniqueByEqualityFn = uniqueByEqualityFn; exports.uniqueByOrder = uniqueByOrder; exports.uniqueByOrderFn = uniqueByOrderFn; exports.uniqueByHash = uniqueByHash; exports.uniqueByHashFn = uniqueByHashFn; exports.uniqueByEqualityWithHash = uniqueByEqualityWithHash; exports.uniqueByEqualityWithHashFn = uniqueByEqualityWithHashFn; exports.uniqueByOrderWithHash = uniqueByOrderWithHash; exports.uniqueByOrderWithHashFn = uniqueByOrderWithHashFn; exports.uniqueAdjacent = uniqueAdjacent; exports.uniqueAdjacentFn = uniqueAdjacentFn; exports.uniqueAdjacentByIdentity = uniqueAdjacentByIdentity; exports.uniqueAdjacentByIdentityFn = uniqueAdjacentByIdentityFn; exports.uniqueAdjacentByEquality = uniqueAdjacentByEquality; exports.uniqueAdjacentByEqualityFn = uniqueAdjacentByEqualityFn; exports.uniqueAdjacentByOrder = uniqueAdjacentByOrder; exports.uniqueAdjacentByOrderFn = uniqueAdjacentByOrderFn; exports.uniqueAdjacentByHash = uniqueAdjacentByHash; exports.uniqueAdjacentByHashFn = uniqueAdjacentByHashFn; exports.sort = sort; exports.sortFn = sortFn; exports.sortBy = sortBy; exports.sortByFn = sortByFn; exports.sortByDescending = sortByDescending; exports.sortByDescendingFn = sortByDescendingFn; exports.forEach = forEach; exports.forEachFn = forEachFn; const nullable_1 = require("@softwareventures/nullable"); const ordered_1 = require("@softwareventures/ordered"); // eslint-disable-next-line @typescript-eslint/unbound-method const nativeSlice = Array.prototype.slice; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeReverse = Array.prototype.reverse; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeConcat = Array.prototype.concat; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeFilter = Array.prototype.filter; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeReduce = Array.prototype.reduce; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeReduceRight = Array.prototype.reduceRight; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeIndexOf = Array.prototype.indexOf; // eslint-disable-next-line @typescript-eslint/unbound-method const nativeFindIndex = Array.prototype.findIndex; /** @internal This implementation is for internal use only, the exported declaration is above */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore duplicate identifier: This is the actual implementation, the exported declaration is above. exports.copy = Array.from; /** @internal This implementation is for internal use only, the exported declaration is above */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore duplicate identifier: This is the actual implementation, the exported declaration is above. exports.isArray = Array.isArray; // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents function isArrayLike(value) { return (typeof value === "object" && value != null && "length" in value && typeof value.length === "number"); } function coerce(array) { return (0, exports.isArray)(array) ? array : (0, exports.copy)(array); } function first(array) { return array.length === 0 ? null : array[0]; } function tail(array) { return nativeSlice.call(array, 1); } function push(array, value) { return [...coerce(array), value]; } function pushFn(value) { return array => push(array, value); } function unshift(array, value) { return [value, ...coerce(array)]; } function unshiftFn(value) { return array => unshift(array, value); } function initial(array) { return array.length === 0 ? [] : nativeSlice.call(array, 0, array.length - 1); } function last(array) { return array.length === 0 ? null : array[array.length - 1]; } /** If the array contains exactly one element, returns that element. * Otherwise, returns null. */ function only(array) { return array.length === 1 ? array[0] : null; } function empty(array) { return array.length === 0; } function notEmpty(array) { return array.length > 0; } function reverse(array) { return nativeReverse.call((0, exports.copy)(array)); } function slice(array, start, end) { return nativeSlice.call(array, start, end); } function sliceFn(start, end) { return array => nativeSlice.call(array, start, end); } function take(array, count) { return nativeSlice.call(array, 0, count); } function takeFn(count) { return array => nativeSlice.call(array, 0, count); } function drop(array, count) { return nativeSlice.call(array, count); } function dropFn(count) { return array => nativeSlice.call(array, count); } function takeWhile(array, predicate) { let i = 0; while (i < array.length && predicate(array[i], i)) { ++i; } return take(array, i); } function takeWhileFn(predicate) { return array => takeWhile(array, predicate); } function takeUntil(array, predicate) { return takeWhile(array, (element, index) => !predicate(element, index)); } function takeUntilFn(predicate) { return array => takeUntil(array, predicate); } function dropWhile(array, predicate) { let i = 0; while (i < array.length && predicate(array[i], i)) { ++i; } return drop(array, i); } function dropWhileFn(predicate) { return array => dropWhile(array, predicate); } function dropUntil(array, predicate) { return dropWhile(array, (element, index) => !predicate(element, index)); } function dropUntilFn(predicate) { return array => dropWhile(array, predicate); } function equal(a, b, elementsEqual = ordered_1.equal) { if (a.length !== b.length) { return false; } for (let i = 0; i < a.length; ++i) { if (!elementsEqual(a[i], b[i])) { return false; } } return true; } function equalFn(b, elementsEqual = ordered_1.equal) { return a => equal(a, b, elementsEqual); } function notEqual(a, b, elementsEqual = ordered_1.equal) { return !equal(a, b, elementsEqual); } function notEqualFn(b, elementsEqual = ordered_1.equal) { return a => notEqual(a, b, elementsEqual); } function prefixMatch(a, b, elementsEqual = ordered_1.equal) { if (a.length < b.length) { return false; } for (let i = 0; i < b.length; ++i) { if (a[i] !== b[i]) { return false; } } return true; } function prefixMatchFn(b, elementsEqual = ordered_1.equal) { return a => prefixMatch(a, b, elementsEqual); } /** @internal This implementation is for internal use only, the exported declaration is above */ // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore duplicate identifier: This is the actual implementation, the exported declaration is above. exports.map = Array.from; function mapFn(f) { return array => Array.from(array, f); } function filter(array, predicate) { return nativeFilter.call(array, predicate); } function filterFn(predicate) { return array => nativeFilter.call(array, predicate); } function exclude(array, predicate) { return filter(array, (element, index) => !predicate(element, index)); } function excludeFn(predicate) { return array => exclude(array, predicate); } function excludeNull(array) { return filter(array, nullable_1.isNotNull); } function excludeFirst(array, predicate) { const result = []; let i = 0; for (; i < array.length; ++i) { const element = array[i]; if (!predicate(element, i)) { result.push(element); } else { break; } } for (++i; i < array.length; ++i) { result.push(array[i]); } return result; } function excludeFirstFn(predicate) { return array => excludeFirst(array, predicate); } function remove(array, value) { return exclude(array, element => element === value); } function removeFn(value) { return array => remove(array, value); } function removeFirst(array, value) { return excludeFirst(array, element => element === value); } function removeFirstFn(value) { return array => removeFirst(array, value); } function fold(array, f, initial) { return nativeReduce.call(array, f, initial); } function foldFn(f, initial) { return array => nativeReduce.call(array, f, initial); } function fold1(array, f) { return nativeReduce.call(array, f); } function fold1Fn(f) { return array => fold1(array, f); } function foldRight(array, f, initial) { return nativeReduceRight.call(array, f, initial); } function foldRightFn(f, initial) { return array => nativeReduceRight.call(array, f, initial); } function foldRight1(array, f) { return nativeReduceRight.call(array, f); } function foldRight1Fn(f) { return array => foldRight1(array, f); } function foldMap(array, f, m, initial) { let accumulator = initial; for (let i = 0; i < array.length; ++i) { accumulator = f(accumulator, m(array[i], i), i); } return accumulator; } function foldMapFn(f, m, initial) { return array => foldMap(array, f, m, initial); } function foldMapRight(array, f, m, initial) { let accumulator = initial; const length = array.length; for (let i = 0; i < array.length; ++i) { accumulator = f(accumulator, m(array[length - i], i), i); } return accumulator; } function foldMapRightFn(f, m, initial) { return array => foldMapRight(array, f, m, initial); } function contains(array, value) { return nativeIndexOf.call(array, value) !== -1; } function containsFn(value) { return array => nativeIndexOf.call(array, value) !== -1; } function indexOf(array, value) { const index = nativeIndexOf.call(array, value); return index === -1 ? null : index; } function indexOfFn(value) { return array => indexOf(array, value); } function lastIndexOf(array, value) { for (let i = array.length - 1; i >= 0; --i) { if (array[i] === value) { return i; } } return null; } function lastIndexOfFn(value) { return array => lastIndexOf(array, value); } function findIndex(array, predicate) { const index = nativeFindIndex.call(array, predicate); return index === -1 ? null : index; } function findIndexFn(predicate) { return array => findIndex(array, predicate); } function findLastIndex(array, predicate) { for (let i = array.length - 1; i >= 0; --i) { if (predicate(array[i], i)) { return i; } } return null; } function findLastIndexFn(predicate) { return array => findLastIndex(array, predicate); } function find(array, predicate) { const index = findIndex(array, predicate); return index == null ? null : array[index]; } function findFn(predicate) { return array => find(array, predicate); } function findLast(array, predicate) { for (let i = array.length - 1; i >= 0; --i) { const element = array[i]; if (predicate(element, i)) { return element; } } return null; } function findLastFn(predicate) { return array => findLast(array, predicate); } function maximum(array, compare) { return internalMaximum(array, compare !== null && compare !== void 0 ? compare : ordered_1.compare); } function maximumFn(compare) { return array => internalMaximum(array, compare !== null && compare !== void 0 ? compare : ordered_1.compare); } function internalMaximum(array, compare) { if (array.length === 0) { return null; } let result = array[0]; for (let i = 1; i < array.length; ++i) { if (compare(array[i], result) > ordered_1.Comparison.equal) { result = array[i]; } } return result; } function maximumBy(array, select) { return maximum(array, (a, b) => (0, ordered_1.compare)(select(a), select(b))); } function maximumByFn(select) { return array => maximumBy(array, select); } function minimum(array, compare) { return internalMinimum(array, compare !== null && compare !== void 0 ? compare : ordered_1.compare); } function minimumFn(compare) { return array => internalMinimum(array, compare !== null && compare !== void 0 ? compare : ordered_1.compare); } function internalMinimum(array, compare) { if (array.length === 0) { return null; } let result = array[0]; for (let i = 1; i < array.length; ++i) { if (compare(array[i], result) < ordered_1.Comparison.equal) { result = array[i]; } } return result; } function minimumBy(array, select) { return minimum(array, (a, b) => (0, ordered_1.compare)(select(a), select(b))); } function minimumByFn(select) { return array => minimumBy(array, select); } function sum(array) { return fold(array, (a, b) => a + b, 0); } function product(array) { return fold(array, (a, b) => a * b, 1); } function average(array) { if (array.length === 0) { return null; } else { return sum(array) / array.length; } } function and(array) { return findIndex(array, element => !element) == null; } function or(array) { return findIndex(array, element => Boolean(element)) != null; } function any(array, predicate) { return findIndex(array, predicate) != null; } function anyFn(predicate) { return array => any(array, predicate); } function all(array, predicate) { return !any(array, (element, index) => !predicate(element, index)); } function allFn(predicate) { return array => all(array, predicate); } function concat(arrays) { return nativeConcat.apply([], (0, exports.map)(arrays, coerce)); } function prepend(a) { return b => concat([a, b]); } function append(b) { return a => concat([a, b]); } function concatMap(array, f) { return concat((0, exports.map)(array, f)); } function concatMapFn(f) { return array => concatMap(array, f); } function noneNull(array) { return any(array, nullable_1.isNull) ? null : array; } function scan(array, f, initial) { const result = (0, exports.copy)({ length: array.length }); let accumulator = initial; for (let i = 0; i < array.length; ++i) { result[i] = accumulator = f(accumulator, array[i], i); } return result; } function scanFn(f, initial) { return array => scan(array, f, initial); } function scan1(array, f) { if (array.length === 0) { return []; } let accumulator = array[0]; const result = (0, exports.copy)({ 0: accumulator, length: array.length }); for (let i = 1; i < array.length; ++i) { result[i] = accumulator = f(accumulator, array[i], i); } return result; } function scan1Fn(f) { return array => scan1(array, f); } function scanRight(array, f, initial) { const result = (0, exports.copy)({ length: array.length }); let accumulator = initial; for (let i = array.length - 1; i >= 0; --i) { result[i] = accumulator = f(accumulator, array[i], i); } return result; } function scanRightFn(f, initial) { return array => scanRight(array, f, initial); } function scanRight1(array, f) { if (array.length === 0) { return []; } let accumulator = array[array.length - 1]; const result = (0, exports.copy)({ [array.length - 1]: accumulator, length: array.length }); for (let i = array.length - 2; i >= 0; --i) { result[i] = accumulator = f(accumulator, array[i], i); } return result; } function scanRight1Fn(f) { return array => scanRight1(array, f); } /** Splits the array at the specified index. * * Returns a tuple where the first element is the first `index` elements of the * array, and the second element is the remaining elements of the array. */ function split(array, index) { return [take(array, index), drop(array, index)]; } /** Returns a function that splits an array at the specified index. * * This is the curried form of {@link split}. */ function splitFn(index) { return array => split(array, index); } function partition(array, predicate) { const a = []; const b = []; for (let i = 0; i < array.length; ++i) { if (predicate(array[i], i)) { a.push(array[i]); } else { b.push(array[i]); } } return [a, b]; } function partitionFn(predicate) { return array => partition(array, predicate); } function partitionWhile(array, predicate) { let i; for (i = 0; i < array.length; ++i) { if (!predicate(array[i], i)) { break; } } return [take(array, i), drop(array, i)]; } function partitionWhileFn(predicate) { return array => partitionWhile(array, predicate); } function partitionUntil(array, predicate) { return partitionWhile(array, element => !predicate(element)); } function partitionUntilFn(predicate) { return array => partitionUntil(array, predicate); } /** Takes two arrays and returns an array of corresponding pairs. * * If one of the supplied arrays is shorter than the other, then the excess * elements of the longer array will be discarded. */ function zip(a, b) { const length = Math.min(a.length, b.length); const result = new Array(length); for (let i = 0; i < length; ++i) { result[i] = [a[i], b[i]]; } return result; } /** Returns a function that combines the elements of `a` with the elements of * `b` and returns an array of corresponding pairs. * * If one of the supplied arrays is shorter than the other, then the excess * elements of the longer array will be discarded. * * This is the curried variant of {@link zip}. */ function zipFn(b) { return a => zip(a, b); } function keyBy(array, f) { var _a; const result = new Map(); for (let i = 0; i < array.length; ++i) { const element = array[i]; const key = f(element, i); const group = (_a = result.get(key)) !== null && _a !== void 0 ? _a : []; if (!result.has(key)) { result.set(key, group); } group.push(element); } return result; } function keyByFn(f) { return array => keyBy(array, f); } function keyFirstBy(array, f) { const result = new Map(); for (let i = 0; i < array.length; ++i) { const element = array[i]; const key = f(element, i); if (!result.has(key)) { result.set(key, element); } } return result; } function keyFirstByFn(f) { return array => keyFirstBy(array, f); } function keyLastBy(array, f) { const result = new Map(); for (let i = 0; i < array.length; ++i) { const element = array[i]; const key = f(element, i); result.set(key, element); } return result; } function keyLastByFn(f) { return array => keyLastBy(array, f); } function mapKeyBy(array, f) { var _a; const result = new Map(); for (let i = 0; i < array.length; ++i) { const [key, element] = f(array[i], i); const group = (_a = result.get(key)) !== null && _a !== void 0 ? _a : []; if (!result.has(key)) { result.set(key, group); } group.push(element); } return result; } function mapKeyByFn(f) { return array => mapKeyBy(array, f); } function mapKeyFirstBy(array, f) { const result = new Map(); for (let i = 0; i < array.length; ++i) { const [key, element] = f(array[i], i); if (!result.has(key)) { result.set(key, element); } } return result; } function mapKeyFirstByFn(f) { return array => mapKeyFirstBy(array, f); } function mapKeyLastBy(array, f) { const result = new Map(); for (let i = 0; i < array.length; ++i) { const [key, element] = f(array[i], i); result.set(key, element); } return result; } function mapKeyLastByFn(f) { return array => mapKeyLastBy(array, f); } function group(array, grouping) { if ("identity" in grouping) { return groupByIdentity(array, grouping.identity); } else if ("compare" in grouping) { if (typeof grouping.hash === "function") { return groupByOrderWithHash(array, grouping.compare, grouping.hash); } else { return groupByOrder(array, grouping.compare); } } else if ("equal" in grouping) { if (typeof grouping.hash === "function") { return groupByEqualityWithHash(array, grouping.equal, grouping.hash); } else { return groupByEquality(array, grouping.equal); } } else { return groupByHash(array, grouping.hash); } } function groupFn(grouping) { return array => group(array, grouping); } function groupByIdentity(array, identity = element => element) { var _a; const groups = []; const map = new Map(); for (let i = 0; i < array.length; ++i) { const element = array[i]; const key = identity(element); const group = (_a = map.get(key)) !== null && _a !== void 0 ? _a : []; group.push(element); if (!map.has(key)) { groups.push(group); map.set(key, group); } } return groups; } function groupByIdentityFn(identity) { return array => groupByIdentity(array, identity); } function groupByEquality(array, equal) { const result = []; outer: for (let i = 0; i < array.length; ++i) { for (let j = 0; j < result.length; ++j) { const group = (0, nullable_1.notNull)(result[j]); if (equal(group[0], array[i])) { group.push(array[i]); continue outer; } } result.push([array[i]]); } return result; } function groupByEqualityFn(equal) { return array => groupByEquality(array, equal); } function groupByOrder(array, compare) { // TODO: This could use a binary tree to be way more efficient return groupByEquality(array, (a, b) => compare(a, b) === ordered_1.Comparison.equal); } function groupByOrderFn(compare) { return array => groupByOrder(array, compare); } function groupByHash(array, hash) { var _a; const groups = new Map(); const result = []; for (let i = 0; i < array.length; ++i) { const element = array[i]; const h = hash(element, i); const group = (_a = groups.get(h)) !== null && _a !== void 0 ? _a : []; if (!groups.has(h)) { result.push(group); groups.set(h, group); } group.push(element); } return result; } function groupByHashFn(hash) { return array => groupByHash(array, hash); } function groupByEqualityWithHash(array, equal, hash) { var _a; const groups = new Map(); const result = []; for (let i = 0; i < array.length; ++i) { const element = array[i]; const h = hash(element, i); const hashGroup = (_a = groups.get(h)) !== null && _a !== void 0 ? _a : []; if (!groups.has(h)) { groups.set(h, hashGroup); } const group = find(hashGroup, group => equal(group[0], element)); if (group == null) { const newGroup = [element]; hashGroup.push(newGroup); result.push(newGroup); } else { group.push(element); } } return result; } function groupByEqualityWithHashFn(equal, hash) { return array => groupByEqualityWithHash(array, equal, hash); } function groupByOrderWithHash(array, compare, hash) { return groupByEqualityWithHash(array, (a, b) => compare(a, b) === ordered_1.Comparison.equal, hash); } function groupByOrderWithHashFn(compare, hash) { return array => groupByOrderWithHash(array, compare, hash); } function groupAdjacent(array, grouping) { if ("identity" in grouping) { return groupAdjacentByIdentity(array, grouping.identity); } else if ("equal" in grouping) { return groupAdjacentByEquality(array, grouping.equal); } else if ("compare" in grouping) { return groupAdjacentByOrder(array, grouping.compare); } else { return groupByHash(array, grouping.hash); } } function groupAdjacentFn(grouping) { return array => groupAdjacent(array, grouping); } function groupAdjacentByIdentity(array, identity) { return identity == null ? groupAdjacentByEquality(array, (a, b) => a === b) : groupAdjacentByEquality(array, (a, b) => identity(a) === identity(b)); } function groupAdjacentByIdentityFn(identity) { return array => groupAdjacentByEquality(array, (a, b) => identity(a) === identity(b)); } function groupAdjacentByEquality(array, equal) { if (array.length === 0) { return []; } let element = array[0]; let group = [element]; const result = [group]; for (let i = 1; i < array.length; ++i) { const prev = element; element = array[i]; if (equal(prev, element)) { group.push(element); } else { group = [element]; result.push(group); } } return result; } function groupAdjacentByEqualityFn(equal) { return array => groupAdjacentByEquality(array, equal); } function groupAdjacentByOrder(array, compare) { return groupAdjacentByEquality(array, (a, b) => compare(a, b) === ordered_1.Comparison.equal); } function groupAdjacentByOrderFn(compare) { return array => groupAdjacentByOrder(array, compare); } function groupAdjacentByHash(array, hash) { if (array.length === 0) { return []; } const element = array[0]; let h = hash(element, 0); let group = [element]; const result = [group]; for (let i = 1; i < array.length; ++i) { const element = array[i]; const h1 = hash(element, i); if (h === h1) { group.push(element); } else { h = h1; group = [element]; result.push(group); } } return result; } function groupAdjacentByHashFn(hash) { return array => groupAdjacentByHash(array, hash); } function unique(array, grouping) { if ("identity" in grouping) { return uniqueByIdentityInternal(array, grouping.identity); } else if ("compare" in grouping) { if (typeof grouping.hash === "function") { return uniqueByOrderWithHash(array, grouping.compare, grouping.hash); } else { return uniqueByOrder(array, grouping.compare); } } else if ("equal" in grouping) { if (typeof grouping.hash === "function") { return uniqueByEqualityWithHash(array, grouping.equal, grouping.hash); } else { return uniqueByEquality(array, grouping.equal); } } else { return uniqueByHash(array, grouping.hash); } } function uniqueFn(grouping) { return array => unique(array, grouping); } function uniqueByIdentity(array, identity) { return uniqueByIdentityInternal(array, identity !== null && identity !== void 0 ? identity : (element => element)); } function uniqueByIdentityInternal(array, identity) { const set = new Set(); const result = []; for (let i = 0; i < array.length; ++i) { const element = array[i]; if (!set.has(identity(element))) { set.add(identity(element)); result.push(element); } } return result; } function uniqueByEquality(array, equal) { const result = []; outer: for (let i = 0; i < array.length; ++i) { const element = array[i]; for (let j = 0; j < result.length; ++j) { if (equal(element, result[j])) { continue outer; } } result.push(element); } return result; } function uniqueByEqualityFn(equal) { return array => uniqueByEquality(array, equal); } function uniqueByOrder(array, compare) { return uniqueByEquality(array, (a, b) => compare(a, b) === ordered_1.Comparison.equal); } function uniqueByOrderFn(compare) { // TODO: This could use a binary tree to be more efficient return array => uniqueByOrder(array, compare); } function uniqueByHash(array, hash) { const seen = new Set(); const result = []; for (let i = 0; i < array.length; ++i) { const element = array[i]; const h = hash(element, i); if (!seen.has(h)) { seen.add(h); result.push(element); } } return result; } function uniqueByHashFn(hash) { return array => uniqueByHash(array, hash); } function uniqueByEqualityWithHash(array, equal, hash) { var _a; const seenGroups = new Map(); const result = []; for (let i = 0; i < array.length; ++i) { const element = array[i]; const h = hash(element, i); const seenGroup = (_a = seenGroups.get(h)) !== null && _a !== void 0 ? _a : []; if (!seenGroups.has(h)) { seenGroups.set(h, seenGroup); } if (all(seenGroup, seenElement => !equal(seenElement, element))) { seenGroup.push(element); result.push(element); } } return result; } function uniqueByEqualityWithHashFn(equal, hash) { return array => uniqueByEqualityWithHash(array, equal, hash); } function uniqueByOrderWithHash(array, compare, hash) { return uniqueByEqualityWithHash(array, (a, b) => compare(a, b) === ordered_1.Comparison.equal, hash); } function uniqueByOrderWithHashFn(compare, hash) { return array => uniqueByOrderWithHash(array, compare, hash); } function uniqueAdjacent(array, grouping) { if ("identity" in grouping) { return uniqueAdjacentByIdentity(array, grouping.identity); } else if ("equal" in grouping) { return uniqueAdjacentByEquality(array, grouping.equal); } else if ("compare" in grouping) { return uniqueAdjacentByOrder(array, grouping.compare); } else { return uniqueAdjacentByHash(array, grouping.hash); } } function uniqueAdjacentFn(grouping) { return array => uniqueAdjacent(array, grouping); } function uniqueAdjacentByIdentity(array, identity) { return identity == null ? uniqueAdjacentByEquality(array, (a, b) => a === b) : uniqueAdjacentByEquality(array, (a, b) => identity(a) === identity(b)); } function uniqueAdjacentByIdentityFn(identity) { return array => uniqueAdjacentByIdentity(array, identity); } function uniqueAdjacentByEquality(array, equal) { if (array.length === 0) { return []; } let element = array[0]; const result = [element]; for (let i = 1; i < array.length; ++i) { const prev = element; element = array[i]; if (!equal(prev, element)) { result.push(element); } } return result; } function uniqueAdjacentByEqualityFn(equal) { return array => uniqueAdjacentByEquality(array, equal); } function uniqueAdjacentByOrder(array, compare) { return uniqueAdjacentByEquality(array, (a, b) => compare(a, b) === ordered_1.Comparison.equal); } function uniqueAdjacentByOrderFn(compare) { return array => uniqueAdjacentByOrder(array, compare); } function uniqueAdjacentByHash(array, hash) { if (array.length === 0) { return []; } const element = array[0]; let h = hash(element, 0); const result = [element]; for (let i = 1; i < array.length; ++i) { const element = array[i]; const h1 = hash(element, i); if (h !== h1) { h = h1; result.push(element); } } return result; } function uniqueAdjacentByHashFn(hash) { return array => uniqueAdjacentByHash(array, hash); } function sort(array, comparator) { return (0, exports.copy)(array).sort(comparator !== null && comparator !== void 0 ? comparator : ordered_1.compare); } function sortFn(comparator) { return array => sort(array, comparator); } function sortBy(array, select) { return sort(array, (a, b) => ordered_1.compare(select(a), select(b))); } function sortByFn(select) { return array => sortBy(array, select); } function sortByDescending(array, select) { return sort(array, (a, b) => -ordered_1.compare(select(a), select(b))); } function sortByDescendingFn(select) { return array => sortByDescending(array, select); } function forEach(array, f) { for (let i = 0; i < array.length; ++i) { f(array[i], i); } return array; } function forEachFn(f) { return array => forEach(array, f); } //# sourceMappingURL=index.js.map