所以我的目标是将一个任意数字的字符串作为数组,将它们分类为匹配字长的子数组,然后置换每个子数组而不改变子数组的顺序并遵循以下规则:
我几乎能够做到这一点,但我一直未能得到所有的排列。我一直在努力解决这个问题,所以我决定环顾四周,现在我来寻求帮助。这是我到目前为止所做的事情(我为这些奇怪的变量名提前道歉):
function* permute(permutation) {
const length = permutation.length;
let c = Array(length).fill(0),
i = 1,
k, p;
yield permutation;
while (i < length) {
if (c[i] < i) {
k = (i % 2) ? c[i] : 0;
p = permutation[i];
permutation[i] = permutation[k];
permutation[k] = p;
++c[i];
i = 1;
yield permutation;
} else {
c[i] = 0;
++i;
}
}
}
function* permuteGroups(input) {
input.sort((a,b) => {return a.length-b.length;});
let groups = [], //Holds the list of Generators and words
groupsCache = [], //Copy of groups to reset the Generators
g = 0, i = input.length, len = input[i - 1].length,
gid = 0, currentGroup, currentSet, finished = [];
//Helper function to reset a Generator
function reset(gid) {
groups[gid] = {
'currentValue': undefined,
'nextValue': undefined,
'generator': permute(groupsCache[gid].split(',')),
'gen2': permute(groupsCache[gid].split(','))
};
groups[gid].nextValue = groups[gid].gen2.next().value.join(',');
}
function fetch(gid, next) {
if (!!next) {
if (groups[gid].generator === undefined) return { 'currentValue': groups[gid].currentValue, 'nextValue': undefined };
let cv = groups[gid].generator.next();
let nv = groups[gid].gen2.next();
cv = (cv.done) ? 'done' : ((cv.value) ? cv.value.join(',') : undefined);
nv = (nv.done) ? 'done' : ((nv.value) ? nv.value.join(',') : undefined);
groups[gid].currentValue = cv;
groups[gid].nextValue = nv;
}
let output = {
'currentValue': groups[gid].currentValue,
'nextValue': groups[gid].nextValue
};
return output;
}
function getOutput(next) {
let gid = 0, len = groups.length, output = [];
while (gid < len) {
output.push(fetch(gid++, next).currentValue);
}
return output;
}
//First move words into sub-arrays based on length
groups.push([]);
while (i--) {
if (input[i].length == len) {
groups[g].push(input[i]);
continue;
}
groups[++g] = [input[i]];
len = input[i].length;
}
groupsCache = groups.map(x => x.join(',')); // Convert each group into a string to preserve order
//Turn the sub-arrays into Generators if they have more than one item
len = groups.length - 1;
while (i++ < len) {
groups[i] = (groups[i].length > 1) ? { 'currentValue': undefined, 'nextValue': undefined, 'generator': permute(groups[i].toString().split(',')), 'gen2': permute(groups[i].toString().split(',')) } : { 'currentValue': groups[i].toString().split(','), 'nextValue': undefined, 'generator': undefined, 'gen2': undefined };
if (groups[i].gen2) groups[i].nextValue = groups[i].gen2.next().value.join(',');
finished[i] = (groups[i].nextValue) ? false : true;
}
//console.log(finished)
//Yield initial output
yield getOutput(true);
let index = 0, isNotDone = true, isInc = false;
while (isNotDone) {
// If we're supposed to be going up to the next group, but there isn't one, reset the index back to zero
// Fetch the next value for the current group...
currentSet = fetch(index, true);
/* default, default, default
/ "rabbit,beaver,calf,wolf,cat,fox,dog"
* Flip [0], default, default
/ "beaver,rabbit,calf,wolf,cat,fox,dog"
* Reset [0], flip [1], default
/ "rabbit,beaver,wolf,calf,cat,fox,dog"
* Flip [0], flipped, default
/ "beaver,rabbit,wolf,calf,cat,fox,dog"
* Reset [0], Reset [1], move [3]
/ "rabbit,beaver,calf,wolf,fox,cat,dog"
*/
// and yield it.
yield getOutput();
// If this was the last value before this group is done...
if (currentSet.nextValue == 'done') {
// if (!groups[index+1] || finished.slice(index+1).every(x => x === true)) {
// finished[index] = true;
// console.log(finished)
// if (finished.every(x => x === true)) {
// isNotDone = false;
// }
// index = 0;
// continue;
// }
// reset the current group
reset(index);
// and put it back on the first value
fetch(index, true);
// Move on to the next group
index++;
// Mark that we plan on going to the next group up
isInc = true;
continue;
}
// Otherwise if it is not the last value and the isInc flag is set
if (isInc) {
// Reset the index back to zero
index = 0;
isInc = false;
}
}
return 'done';
}
let perm = permuteGroups(['dog','fox','cat','wolf','calf','beaver','rabbit']);
let result = perm.next();
while (!result.done) {
console.log(result.value.toString());
result = perm.next();
}
从它休息了一段时间后,我设法让它按照需要工作。这是未来任何人的最终结果。它可以按原样推送到Codepen中并开始工作,但我建议使用较小的单词列表,或者在填满你的控制台后它会挂起。我只是离开我的示例列表来展示它可以处理的内容。
我的第一种方法的主要问题是如果我们需要升级到下一组,当一台发电机工作正常时,我们会试着预先处理。
function* permute(permutation) {
const length = permutation.length;
let c = Array(length).fill(0),
i = 1, k;
yield permutation;
while (i < length) {
if (c[i] < i) {
k = (i % 2) ? c[i] : 0;
[permutation[i], permutation[k]] = [permutation[k], permutation[i]];
++c[i];
i = 1;
yield permutation;
} else {
c[i] = 0;
++i;
}
}
}
function* permuteGroups(input) {
input.sort((a,b) => {return a.length-b.length;});
let groups = [], //Holds the list of Generators and words
groupsCache = [], //Copy of groups to reset the Generators
g = 0, i = input.length, len = input[i - 1].length,
gid = 0, currentGroup, currentSet;
//Helper function to reset a Generator
function reset(gid) {
groups[gid] = {
'currentValue': undefined,
'generator': permute(groupsCache[gid].split(','))
};
}
function fetch(gid, next) {
let group = groups[gid];
// IF next and next === true
if (!!next) {
if (group.generator === undefined) return { 'currentValue': group.currentValue };
let cv = group.generator.next();
group.currentValue = (cv.done ? 'done' : (cv.value ? cv.value.join(',') : undefined));
}
return {
'currentValue': group.currentValue
};
}
function getOutput(next) {
return groups.map((group, index) => fetch(index, next).currentValue);
}
//First move words into sub-arrays based on length
groups.push([]);
while (i--) {
if (input[i].length == len) {
groups[g].push(input[i]);
continue;
}
groups[++g] = [input[i]];
len = input[i].length;
}
groupsCache = groups.map(x => x.join(',')); // Convert each group into a string to preserve order
//Turn the sub-arrays into Generators if they have more than one item
groups = groups.map(group => (group.length > 1 ? { 'currentValue': undefined, 'generator': permute(group.toString().split(',')) } : { 'currentValue': group.toString().split(','), 'generator': undefined }) );
//Yield initial output
yield getOutput(true);
let index = 0, isInc = false;
while (true) {
// If we're supposed to be going up to the next group, but there isn't one, reset the index back to zero
// Fetch the next value for the current group...
currentSet = fetch(index, true);
// If this was the last value before this group is done...
if (currentSet.currentValue == 'done' || Array.isArray(currentSet.currentValue)) {
// reset the current group
reset(index);
// and put it back on the first value
fetch(index, true);
// Move on to the next group
index++;
if (index === groups.length) {
// We're done!
return;
}
// Mark that we plan on going to the next group up
isInc = true;
continue;
}
// and yield it.
yield getOutput();
// Otherwise if it is not the last value and the isInc flag is set
if (isInc) {
// Reset the index back to zero
index = 0;
isInc = false;
}
}
}
// "yourself","hero","entire","blank","peg","usage","tot","debate","volt","lie","almond","baseball","sell","youngster","use","atom","left","sit","even","input","only","freight"
let perm = permuteGroups(["yourself","hero","entire","blank","peg","usage","tot","debate","volt","lie","almond","baseball","sell","youngster","use","atom","left","sit","even","input","only","freight"]), i = 1;
let result = perm.next();
while (!result.done) {
console.log(i++, result.value.toString());
result = perm.next();
}