将数组分割成具有动态大小的固定n块

时间:2022-08-25 19:36:06

I have an array say,

我有一个数组,

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

var =[1、2、3、4、5);

which I want to split into exactly n number of chunks but having all the combinations in it.

我想把它分成n个块,但所有的组合都在里面。

Example:

例子:

whenn=3 should return

whenn = 3应该返回

combination1: [1],[2],[3,4,5]

combination1:[1],[2],[3、4、5)

combination2: [1,2],[3,4],[5]

combination2:[1,2],[3,4],[5]

combination3: [1,2,3],[4],[5]

combination3:[1,2,3],[4],[5]

combination4: [1,2],[3],[4,5]

combination4:[1,2],[3],[4,5]

combination5: [1],[2,3],[4,5]

combination5:[1],[2、3],(4、5)

combination6: [1],[2,3,4],[5]

combination6:[1],[2、3、4],[5]

I am not able to understand where to start and stop this combination logic. Any kind of pointer or help is much appreciated.

我不明白从哪里开始和停止这种组合逻辑。任何形式的指针或帮助都是非常感谢的。

2 个解决方案

#1


2  

You could use a recursive approach for getting all nested parts and iterate only the rest length of the left over array.

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

Basically, you need an exit condition, which is met, if the length of the wanted array is equal to the number of items. Then push the result and exit the function.

基本上,您需要一个退出条件,如果想要的数组的长度等于项目的数量,则满足这个条件。然后按下结果并退出函数。

If not, then iterate over the left array and move a new part to the temporary array.

如果没有,则迭代左数组并将一个新部分移动到临时数组。

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)); });

#2


2  

I'd use a slightly different implementation than Nina.

我将使用与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") )

#1


2  

You could use a recursive approach for getting all nested parts and iterate only the rest length of the left over array.

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

Basically, you need an exit condition, which is met, if the length of the wanted array is equal to the number of items. Then push the result and exit the function.

基本上,您需要一个退出条件,如果想要的数组的长度等于项目的数量,则满足这个条件。然后按下结果并退出函数。

If not, then iterate over the left array and move a new part to the temporary array.

如果没有,则迭代左数组并将一个新部分移动到临时数组。

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)); });

#2


2  

I'd use a slightly different implementation than Nina.

我将使用与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") )