dontfreakout
4/16/2015 - 12:58 PM

distribute.js

// Takes [count] of items and the [partition] (array of percentages) to 
// distribute against. Returns an array of integers that sums to [count]:
// an integer composition weighted by the partition.
//
// We don't use the Bresenham algorithm because it doesn't provide the best 
// results for low values of [count].
function DISTRIBUTE(count, partition) {
  // Custom function in Apps Script takes a 2D array. We're only interested in 
  // the first row.
  partition = partition[0];
  
  // First, distribute rounded down, but keep the remainders for each bin.
  var result = [];
  var remainders = [];
  var alreadyDistributedCount = 0;
  for (var i = 0; i < partition.length; i++) {
    var currentCount = Math.floor(partition[i] * count);
    var remainder = partition[i] * count - currentCount;
    result.push(currentCount);
    remainders.push(remainder);
    alreadyDistributedCount += currentCount;
  }

  // Now iteratively add [partition] values to corresponding remainders.
  var j = 0;
  while (alreadyDistributedCount < count) {
    remainders[j] += partition[j];
    if (remainders[j] > 1) {
      result[j] += 1;
      remainders[j] -= 1;
      alreadyDistributedCount += 1;
    }
    j += 1;
    if (j >= partition.length) j = 0;
  }
  
  // Apps Script expects 2D array output. We only provide one row.
  return [result];
}