Reputation:
I have the following array:
var myNumbers = [70.37037037037037, 11.11111111111111, 11.11111111111111, 7.4074074074074066];
I need each number to be rounded and all of their sum to total 100. If they fall short the difference will be made up for by adding 1 to items in decreasing order of their decimal parts. This is called the Largest Remainder Method
(and I got the following code form How to make rounded percentages add up to 100%). Here's the underscore code to get this:
var off = 100 - _.reduce(myNumbers, function(acc, x) {
return acc + Math.round(x)
}, 0);
var rounded_percentages = _.chain(myNumbers)
.sortBy(function(x) {
return Math.round(x) - x
})
.map(function(x, i) {
return Math.round(x) + (off > i) - (i >= (myNumbers.length + off))
})
.value();
The result is:
[8, 70, 11, 11]
This works great but the order is not preserved. How can I achieve the above while either preserving the order or do the whole operation with an object instead of an array and have the proper key mapping retained?
With the order preserved it should result in:
[70, 11, 11, 8]
With key mapping the initial var would look like:
var myNumbers = {
firstNum: 70.37037037037037,
secondNum: 11.11111111111111,
thirdNum: 11.11111111111111,
fourthNum: 7.4074074074074066
};
and the result would be:
{
fourthNum: 8,
firstNum: 70,
secondNum: 11,
thirdhNum: 11
};
Upvotes: 0
Views: 999
Reputation: 665130
Don't change the order of the array at all. Do only create a permutation (an array of indexes that is then sorted by a property of the array value each index points to), and play your algorithm on that.
var rounded_percentages = _.map(myNumbers, Math.floor);
var off = _.reduce(rounded_percentages, function(acc, x) { return acc - x; }, 100);
var permutation = _.sortBy(_.map(myNumbers, function(_, i) { return i; }), function(i) {
return rounded_percentages[i] - myNumbers[i]; // those with the largest diff first
});
for (var i=0; i<off; i++)
rounded_percentages[permutation[i]]++
Which is a much closer implementation of the Largest Remainder Method, the Math.round
in your implementation is odd.
Upvotes: 1