【问题标题】:split array into fixed n chunks with dynamic sizes将数组拆分为具有动态大小的固定 n 个块
【发布时间】:2017-03-16 08:44:26
【问题描述】:

我有一个数组说,

var a = [1,2,3,4,5];

我想将其拆分为精确的 n 个块,但其中包含所有组合。

例子:

n=3 应该返回时

组合1:[1],[2],[3,4,5]

组合2:[1,2],[3,4],[5]

组合3:[1,2,3],[4],[5]

组合4:[1,2],[3],[4,5]

组合5:[1],[2,3],[4,5]

组合6:[1],[2,3,4],[5]

我无法理解从哪里开始和停止这种组合逻辑。非常感谢任何类型的指针或帮助。

【问题讨论】:

  • 你是如何“产生”你展示的组合的?
  • @Thomas n = 块数,每个块中至少应包含一个元素。因此,当 n = 3 时,我手动记下所有组合。这些是我想通过 javascript 打印出来的组合。
  • 好的,但是你是怎么想出你写下的组合的?你掷骰子了吗? 小指针:按以下顺序重新排列您的组合:1、5、6、4、2、3,也许您在组之间添加 2 或 3 个空格。你看到模式了吗? 我的意思是,你已经解决了这个问题,所以你能够理解这个组合逻辑。也许您在将这个逻辑放入代码时遇到问题?然后我们就可以着手解决了。
  • @Thomas 是的,我在将逻辑放入代码时遇到问题。我无法获得应该为循环开始和何时终止循环设置什么条件。

标签: javascript arrays combinations


【解决方案1】:

我会使用与 Nina 稍有不同的实现。

function combinations(n, values, log){
  if(n > values.length) 
    throw new Error(`cannot divide ${values.length} items into ${n} groups`);
  
  var results = [], 
    //you'll always have n items in your combination, by the very definition of this task
    //this array holds the state/progress during the iterations, 
    //so we don't have to concat partial results all the time
    //we'll push clones of the current state to the results.
    combination = Array(n);

  //just a utility to write a chunk to a particular index
  function updateIndex(index, left, right){
    combination[index] = values.slice(left, right);
    log && log(index, "updateIndex(" + [index, left, right] + ")", JSON.stringify(combination[index]));
  }
  
  //And by the good old Roman principle: divide et impera
  //this function always processes a subset of the array, defined by the bounds: left and right.
  //where `left <= index < right` (so it doesn't include right)
  //it is a recursive function, so it processes one chunk at a time, and calls itself to process the rest of the array
  function divide(index, chunks, left, right){
    log && log(index, "divide(" + [index, chunks, left, right] + ")", JSON.stringify(values.slice(left, right)) + " divided by " + chunks);
    if(chunks > 1){
      //I have to divide my section of the array in mutliple chunks
      //I do that by defining a pivot
      //the range where I can pivot is limited: 
      //  - I need at least 1 item to the left for the current chunk
      //  - and I need at least (chunks-1) items to the right for the remaining subdivisions
      for(var pivot = left + 1; pivot <= right - (chunks-1); ++pivot){
        //everything on the left of this pivot is the current chunk
        //write it into the combinations array at the particular index
        updateIndex(index, left, pivot);
        //everything on the right is not my buisness yet.
        //I'll call divide() again, to take care of that
        divide(index+1, chunks-1, pivot, right);
      }
    }else{
      //this is the last chunk, write this whole section to the last index
      updateIndex(index, left, right);
      //push a clone of this combination to the results
      //because further iterations in the loops, will change the values of the original
      //to produce the remaining combinations
      results.push(combination.slice());
      log && log(index, "push(" + formatCombination(combination) + ")\n");
    }
    return results
  }
  
  return divide(0, n, 0, arr.length);
}

function formatCombination(row){
  return JSON.stringify(row).replace(/\],\[/g, "],  [");
}

//an utility to log the steps in a nice fashion
function logger(indentation, fnText, memo){
  var str = "  ".repeat(indentation) + fnText;
  console.log(memo? str + " ".repeat(60-str.length) + memo: str);
}


var arr = [0,1,2,3,4,5];
var result = combinations(3, arr, logger);

console.log();
console.log( result.map(formatCombination).join("\n") )

【讨论】:

  • 不错的替代方法,所有的 cmets 都对我理解代码很有帮助。
【解决方案2】:

您可以使用递归方法获取所有嵌套部分并仅迭代剩余数组的剩余长度。

基本上,如果所需数组的长度等于项目数,则需要满足退出条件。然后推送结果并退出函数。

如果不是,则遍历左侧数组并将新部分移动到临时数组中。

function go(array, n) {
    function iter(left, right) {
        var i,
            l = left.length - n + right.length + 1;
        
        if (right.length + 1 === n) {                
            result.push(right.concat([left]));
            return;
        }
        for (i = 1; i <= l; i++) {
            iter(left.slice(i), right.concat([left.slice(0, i)]));
        }
    }

    var result = [];
    iter(array, []);
    return result;
}


var array = [1, 2, 3, 4, 5],
    n = 3,
    result = go(array, n);

result.forEach(function (a) { console.log(JSON.stringify(a)); });

【讨论】:

  • 谢谢,@Nina。这正是我想要完成但不知道如何完成的。
猜你喜欢
  • 2020-01-14
  • 2020-09-16
  • 1970-01-01
  • 1970-01-01
  • 2017-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多