Search code examples
arraysalgorithmdivisioninteger-division

How to divide an integer into an array of roughly equal and evenly distributed parts that sum to the original integer?


Given an integer n, what is an algorithm that can divide it into an array of d parts, which has the properties that its members sum to the original integer n, are roughly equal in size, and are reasonably evenly distributed throughout the array? e.g. dividing 13 into 10 parts looks something like:

[1, 1, 2, 1, 1, 2, 1, 1, 2, 1]

More specifically, it shouldn't look like:

[1, 1, 1, 1, 1, 1, 1, 2, 2, 2] (uneven distribution)

[1, 1, 1, 1, 1, 1, 1, 1, 1, 4] (not roughly equal in size)

The parity of the array's members is not important.


Solution

  • One way is to use a dynamic ratio (a/b) in relation to the ratio of the large values to small values (c/r) in order to decide the distribution of the remainder after division:

    function split(n, d)
    {
      if(d === 0)
        return [];
    
      // Integer division spelled in JavaScript
      const q = Math.floor(n / d);
      const r = n % d;
      const c = d - r;
      
      let out = Array(d);
      let a = 1;
      let b = 1;
      
      for(let i = 0; i < d; i++)
      {
        // Make the ratio a/b tend towards c/r
        if((a * r) < (b * c))
        {
          a++;
          out[i] = q;
        }
        else
        {
          b++;
          out[i] = q + 1;
        }
      }
      
      // Check the array sums to n
      console.log(out, n === out.reduce((a, b) => a + b, 0));
    
      return out;
    }
    
    split(11, 10);
    split(173, 9);
    split(13, 10);
    split(1773, 19);
    

    This produces the output:

    [1, 1, 1, 1, 1, 1, 1, 1, 2, 1], true
    [19, 19, 19, 20, 19, 19, 19, 20, 19], true
    [1, 1, 2, 1, 1, 2, 1, 1, 2, 1], true
    [93, 93, 94, 93, 93, 94, 93, 93, 94, 93, 93, 94, 93, 93, 94, 93, 93, 94, 93], true