获取子阵列的排列而不改变子阵列的顺序

问题描述 投票:0回答:1

所以我的目标是将一个任意数字的字符串作为数组,将它们分类为匹配字长的子数组,然后置换每个子数组而不改变子数组的顺序并遵循以下规则:

  1. 如果任何组只有一个单词,则保持原样。 (即['猫'])
  2. 置换第一组直到完成。
  3. 将第二组置换一次,然后执行第1步;每次完成步骤1时,仅对第二组进行一次置换。
  4. 将第三组置换一次,然后执行第2步;每次完成第2步时,只会置换第三组。
  5. 继续此模式,直到完成所有组。

我几乎能够做到这一点,但我一直未能得到所有的排列。我一直在努力解决这个问题,所以我决定环顾四周,现在我来寻求帮助。这是我到目前为止所做的事情(我为这些奇怪的变量名提前道歉):

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();
}
javascript arrays generator permutation
1个回答
0
投票

从它休息了一段时间后,我设法让它按照需要工作。这是未来任何人的最终结果。它可以按原样推送到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();
}
© www.soinside.com 2019 - 2024. All rights reserved.