permutations.mjs

/**
 * Creates a permutations generator from a specified size or an array of elements.
 * 
 * @param {number|Array} sizeOrArr Integer size or an array of items
 * @yields {Array} Re-arranged array of items/indices
 */
export const permutationsIterator = function*(sizeOrArr) {
  const arr = Array.isArray(sizeOrArr) ? [...sizeOrArr] : new Array(sizeOrArr).fill(0).map((_, i) => i);
  const size = arr.length;

  const gen = function*(res, used, shift) {
    const len = size - used;
    if (len === 0) {
      yield res;
      return;
    }
    for (let i = 0; i < len; ++i) {
      yield* gen([...res, shift[i]], used + 1, [...shift.slice(0, i), ...shift.slice(i + 1)]);
    }
  };

  yield* gen([], 0, arr);
};

/**
 * Returns all permutations synchronously.
 * WARNING: Generates size! (factorial) elements. Scales in O(N!). 
 * 
 * @param {number|Array} sizeOrArr 
 * @returns {Array<Array>} Array of permutation sets
 */
export const permutations = (sizeOrArr) => {
  return [...permutationsIterator(sizeOrArr)];
};