matrix.ts•1.32 kB
/* eslint-disable @typescript-eslint/no-unsafe-argument */
import type { L } from 'ts-toolbelt'
import { flatten } from './flatten'
import { map } from './map'
import { repeat, times } from './repeat'
import { select } from './select'
import type { Strict } from './utils/types/Strict'
/**
 * Recursive function that is able to create a matrix of lists.
 * The algorithm is quite simple and recursively applies a map.
 * @example
 * map(lists[0], (item0) => map(lists[1], (item1) => map(lists[2], (...) => [item0, item1, ...])))
 */
function _matrix<I>(lists: L.List<L.List<I>>, items: L.List<I> = []) {
  if (items.length === lists.length) return items
  return map(lists[items.length], (item) => _matrix(lists, [...items, item]))
}
/**
 * Creates the cross-product of a list of lists.
 *
 * @param lists
 * @returns
 */
function matrix<I extends L.List>(lists: L.List<I>): Strict<I[number]>[][] {
  // we cannot produce a matrix with empty lists, filter them out
  const nonEmptyLists = select(lists, (list) => list.length > 0)
  const nonFlatMatrix = _matrix(nonEmptyLists) // first raw matrix
  const flattenMatrix = repeat(flatten, times(nonEmptyLists.length - 1))
  // we flatten the matrix as many times as it had recursion levels
  return flattenMatrix(nonFlatMatrix) // final flat matrix
}
export { matrix }