Frage

I'm trying to split an array into chunks. The chunks should be as many as the function specifies. What I have already is

groupBySize = function(array, groupSize){
    if(groupSize === 0){
        return;
    }
    var groups = [];
    var i,j,temparray;
    for (i=0,j=array.length; i<j; i+=groupSize) {
        temparray = array.slice(i,i+groupSize);
        groups.push(temparray);
    }
    return groups;
};
groupByNumberOfGroups = function(array, NumberOfGroups){
    var groupSize = Math.floor(array.length/NumberOfGroups);
    var groups = this.groupBySize(array, groupSize);
    // Let's make sure we get the right amount of groups
    while(groups.length > NumberOfGroups){
        console.log(groups.length + ">" + NumberOfGroups);
        var last = groups[(groups.length-1)];
        for(var j = 0; j< last.length; j++){
            var temp = j;
            while(groups[temp].length > groups[temp+1]){
                temp++;
            }
            groups[j].push(last[j]);
        }
        groups.pop();
    }
    return groups;
};

This successfully splits the array up into the correct amount of chunks. I would like it to then make the length of each chunk as uniform as possible so if I were to split up an array like [1,2,3,4,5,6] into 4 chunks i would get [[1,2],[3,4],[5],[6]]. Any suggestions?

Another example of shortcomings: splitting up [1,2,3,4,5,6,7,8,9,10,11,12,13,14] into 8 chunks gives [[1,2,3,4,5,6,7],[8],[9],[10],[11],[12],[13],[14]]

War es hilfreich?

Lösung

Simple maths. If You have n items and want to split them into k chunks, every chunk will have n / k items. But what if n / k isn't an integer? Then some of the chunks will have n / k rounded down items and some will have n / k rounded down + 1 items. How many of them will have the + 1 items? n % k.

function distribute(a, k) { 

    var count = Math.floor(a.length / k); 
    var remain = a.length % k; 
    var result = []; 
    var index = 0; 

    for (var i = 0; i < k; i++) { 

        var number = count + (i < remain ? 1 : 0); 
        result.push(a.slice(index, index + number));
        index += number; 
    } 

    return result; 
}

distribute([1, 2, 3, 4, 5, 6, 7], 2);

--> [[1, 2, 3, 4], [5, 6, 7]]

Edit by Nordfjord: Shorter, but groups different values than the solution above:

groupByNumberOfGroups = function(array, numberOfGroups){
    var groups = []
    for(var i = 0; i < numberOfGroups; ++i) groups.push([]);
    for(var i = 0; i < array.length; ++i) groups[i%numberOfGroups].push(array[i]);
    return groups;
}

Andere Tipps

Try this,

var groupByNumberOfGroups = function( array, NumberOfGroups ){
    var div = Math.floor( array.length / NumberOfGroups );
    var mod = array.length % NumberOfGroups;
    var result = [];

    var lowerBound=0, upperBound=0;
    for ( var k=0; k<NumberOfGroups; k++ ) {
        lowerBound = ( upperBound === 0 ) ? ( ( k < mod ) ? k * ( div + 1 ) : k * ( div ) ) : upperBound
        upperBound = ( k < mod ) ? ( lowerBound + div + 1 ) : ( lowerBound + div )
        result[ k ] = array.slice( lowerBound, upperBound );
    }
    return result;
};

groupByNumberOfGroups([1,2,3,4,5,6], 4); // [[1, 2], [3, 4], [5], [6]]
groupByNumberOfGroups([1,2,3,4,5,6,7,8,9,10,11,12,13,14], 8); // [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13], [14]] 

js fiddle : link

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top