UNPKG

custom-permutation

Version:
206 lines 9.49 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PermutationGeneratorForSet = void 0; class PermutationGeneratorForSet { constructor(elementList, indexList, choicesByIndex, indexesOfSameElements, actualOrderOfElements, passFunction) { this.elementList = elementList; this.indexList = indexList; this.choicesByIndex = choicesByIndex; this.indexesOfSameElements = indexesOfSameElements; this.actualOrderOfElements = actualOrderOfElements; this.passFunction = passFunction; this.choicesArraysInitial = []; // possible choices for each element for requested permutations this.choicesArrays = []; // possible choices for each element for requested permutations this.size = 0; this.currentIndsOfChoices = []; // indice array of current perm to compose this.currentElInd = 0; // indice of current elemet to add in perm list this.newPerm = []; this.initialIndexList = []; // original set for new permutation this.visitedDict = {}; this.actualOrderOfElements = this.actualOrderOfElements || Array(indexList.length) .fill(1) .map((el, i) => i); this.indexesOfSameElements = this.indexesOfSameElements || Array(indexList.length) .fill(1) .map((el, i) => i); if (!this.validateParameters(indexList, choicesByIndex)) { return; } indexList = Array.from(new Set(indexList)); this.initialIndexList = indexList; this.size = indexList.length; this.initChoicesArray(); this.reorderListAndChoicesAccordingToChoicesCount(); this.currentIndsOfChoices[this.size - 1] = -1; this.init(); } isNewPermutationPassingFunction(currentEl, elIndInPerm) { const newPerm = this.newPerm.slice(); newPerm[elIndInPerm] = currentEl; const actualOrderedNewPerm = this.revertResultPermToInitialOrder(newPerm); if (this.passFunction) { const elArray = []; actualOrderedNewPerm.forEach((elInd, i) => (elArray[i] = this.elementList[elInd])); const passed = this.passFunction(elArray.filter((x) => x)); // Remove nulls, since some array elements are undefined when building return passed; } return true; } // Change choice arrays elements order to take low choices front to place them firstly reorderListAndChoicesAccordingToChoicesCount() { this.indexesAndChoicesCounts = []; this.choicesArrays.forEach((list, ind) => this.indexesAndChoicesCounts.push({ index: ind, length: list.length })); this.indexesAndChoicesCountsSortedByLength = this.indexesAndChoicesCounts .slice() .sort((el1, el2) => (el1.length < el2.length ? -1 : el1.length === el2.length && el1.index < el2.index ? -1 : 1)); const newChoicesArray = []; const newSet = []; for (let i = 0; i < this.indexesAndChoicesCountsSortedByLength.length; i++) { newChoicesArray[i] = this.choicesArrays[this.indexesAndChoicesCountsSortedByLength[i].index]; newSet[i] = this.indexList[this.indexesAndChoicesCountsSortedByLength[i].index]; } this.choicesArrays = newChoicesArray; this.choicesArraysInitial = JSON.parse(JSON.stringify(this.choicesArrays)); } initChoicesArray() { this.choicesArrays = []; this.choicesArraysInitial = []; for (let i = 0; i < this.indexList.length; i++) { this.choicesArrays.push(this.choicesByIndex[i] && this.choicesByIndex[i].length ? this.choicesByIndex[i].slice() : this.indexList.slice()); this.choicesArraysInitial.push(this.choicesArrays[i].slice()); } } init() { for (let i = 0; i < this.size; i++) { for (let j = 0; j < this.choicesArrays[i].length; j++) { if (this.newPerm.indexOf(this.choicesArrays[i][j]) < 0) { this.newPerm[i] = this.choicesArrays[i][j]; this.visitedDict[this.newPerm[i]] = true; // used this.currentIndsOfChoices[i] = j; break; } } } this.currentIndsOfChoices[this.size - 1] = -1; this.visitedDict[this.newPerm[this.size - 1]] = false; this.newPerm[this.size - 1] = null; } next() { let nextPerm = this.getNextPerm(); if ((nextPerm === null || nextPerm === void 0 ? void 0 : nextPerm.length) > 0) { while (nextPerm.filter((x) => x || x === 0).length < nextPerm.length) { nextPerm = this.getNextPerm(); if (!nextPerm || nextPerm.length === 0) { return { done: true }; } } return { done: false, value: this.revertResultPermToInitialOrder(nextPerm) }; } else { return { done: true }; } } getNextPerm() { for (let i = this.size - 1; i >= 0 && i < this.size; i++) { let choicesArray = []; choicesArray = this.choicesArraysInitial[i].filter((x) => !this.visitedDict[x]); const el = this.getAndSetPossibleNextElementForNewPerm(this.newPerm, choicesArray, this.currentIndsOfChoices, i); if (el === undefined) { if (!this.newPerm.some((x) => x === null)) { return this.newPerm.slice(); } while (!this.goBack(this.newPerm, this.choicesArrays, this.currentIndsOfChoices, --i)) { if (i <= 0) { return undefined; } } } else { this.newPerm[i] = el; this.visitedDict[this.newPerm[i]] = true; } } return this.newPerm.slice(); } goBack(newPerm, choicesArrayWithIndexes, selectedIndexesForPerm, elInd) { if (elInd + 1 < choicesArrayWithIndexes.length) { choicesArrayWithIndexes[elInd + 1] = this.choicesArraysInitial[elInd + 1].slice(); selectedIndexesForPerm[elInd + 1] = -1; this.visitedDict[newPerm[elInd + 1]] = false; newPerm[elInd + 1] = null; } if (elInd >= 0 && elInd < this.size) { choicesArrayWithIndexes[elInd] = this.choicesArraysInitial[elInd].slice(); if (selectedIndexesForPerm[elInd] === choicesArrayWithIndexes[elInd].length - 1) { return false; } else { selectedIndexesForPerm[elInd]++; if (!this.visitedDict[choicesArrayWithIndexes[elInd][selectedIndexesForPerm[elInd]]] && this.isNewPermutationPassingFunction(choicesArrayWithIndexes[elInd][selectedIndexesForPerm[elInd]], elInd)) { this.visitedDict[newPerm[elInd]] = false; newPerm[elInd] = choicesArrayWithIndexes[elInd][selectedIndexesForPerm[elInd]]; this.visitedDict[newPerm[elInd]] = true; return true; } else { return this.goBack(newPerm, choicesArrayWithIndexes, selectedIndexesForPerm, elInd); } } } } getAndSetPossibleNextElementForNewPerm(newPerm, choices, currentIndsInChoices, elInd) { if (currentIndsInChoices[elInd] < 0) { currentIndsInChoices[elInd] = 0; } else { currentIndsInChoices[elInd]++; } if (currentIndsInChoices[elInd] >= 0 && currentIndsInChoices[elInd] < choices.length) { if (!this.isNewPermutationPassingFunction(choices[currentIndsInChoices[elInd]], elInd)) { return this.getAndSetPossibleNextElementForNewPerm(newPerm, choices, currentIndsInChoices, elInd); } newPerm[elInd] = choices[currentIndsInChoices[elInd]]; this.visitedDict[newPerm[elInd]] = true; this.choicesArrays[elInd] = this.choicesArrays[elInd].filter((x) => this.indexesOfSameElements[newPerm[elInd]] && this.indexesOfSameElements[newPerm[elInd]].indexOf(x) === -1); return choices[currentIndsInChoices[elInd]]; } else { this.visitedDict[newPerm[elInd]] = false; currentIndsInChoices[elInd] = -1; newPerm[elInd] = null; return undefined; } } validateParameters(elementSet, choicesByIndex) { if (!elementSet || elementSet.length === 0) { return false; } for (const key in choicesByIndex) { if (!choicesByIndex[key]) { continue; } for (const anotherKey of choicesByIndex[key]) { if (elementSet.indexOf(anotherKey) < 0) { return false; } } } return true; } revertResultPermToInitialOrder(newPerm) { const resultPerm = []; for (let i = 0; i < newPerm.length; i++) { resultPerm[this.indexesAndChoicesCountsSortedByLength[i].index] = newPerm[i]; } return resultPerm; } } exports.PermutationGeneratorForSet = PermutationGeneratorForSet; //# sourceMappingURL=PermutationGeneratorForSet.js.map