注意:选择的答案是更改不首选的数组顺序,在这里我提供了更多不同的变体,以实现相同的结果并保持数组的顺序
讨论
鉴于[98.88, .56, .56]
你想如何舍入它?你有四个选择
1-四舍五入并从其余数字中减去添加的内容,因此结果变为[98, 1, 1]
这可能是一个很好的答案,但如果我们有[97.5, .5, .5, .5, .5, .5]
呢?那么你需要把它四舍五入到[95, 1, 1, 1, 1, 1]
你知道它是怎么回事吗?如果您添加更多类似 0 的数字,您将失去其他数字的更多价值。当你有一大堆类似零的数字时,这可能会非常麻烦,比如[40, .5, .5 , ... , .5]
. 当你四舍五入时,你可能会得到一系列的:[1, 1, .... , 1]
所以围捕不是一个好的选择。
2-你把数字四舍五入。所以[98.88, .56, .56]
变成[98, 0, 0]
,那么你比 100 少 2。你忽略任何已经是 0 的东西,然后将差值加到最大的数字上。所以更大的数字会得到更多。
3- 与前面相同,向下舍入数字,但您根据小数降序排序,根据小数除以差异,因此最大的小数将获得差异。
4-你四舍五入,但你将你添加的内容添加到下一个数字。所以就像波浪一样,您添加的内容将被重定向到数组的末尾。所以[98.88, .56, .56]
变成[99, 0, 1]
这些都不是理想的,因此请注意您的数据将失去其形状。
在这里,我提供了案例 2 和 3 的代码(因为当您有很多类似零的数字时,案例 1 不实用)。它是现代 Js,不需要使用任何库
第二种情况
const v1 = [13.626332, 47.989636, 9.596008, 28.788024];// => [ 14, 48, 9, 29 ]
const v2 = [16.666, 16.666, 16.666, 16.666, 16.666, 16.666] // => [ 17, 17, 17, 17, 16, 16 ]
const v3 = [33.333, 33.333, 33.333] // => [ 34, 33, 33 ]
const v4 = [33.3, 33.3, 33.3, 0.1] // => [ 34, 33, 33, 0 ]
const v5 = [98.88, .56, .56] // =>[ 100, 0, 0 ]
const v6 = [97.5, .5, .5, .5, .5, .5] // => [ 100, 0, 0, 0, 0, 0 ]
const normalizePercentageByNumber = (input) => {
const rounded: number[] = input.map(x => Math.floor(x));
const afterRoundSum = rounded.reduce((pre, curr) => pre + curr, 0);
const countMutableItems = rounded.filter(x => x >=1).length;
const errorRate = 100 - afterRoundSum;
const deductPortion = Math.ceil(errorRate / countMutableItems);
const biggest = [...rounded].sort((a, b) => b - a).slice(0, Math.min(Math.abs(errorRate), countMutableItems));
const result = rounded.map(x => {
const indexOfX = biggest.indexOf(x);
if (indexOfX >= 0) {
x += deductPortion;
console.log(biggest)
biggest.splice(indexOfX, 1);
return x;
}
return x;
});
return result;
}
第三种情况
const normalizePercentageByDecimal = (input: number[]) => {
const rounded= input.map((x, i) => ({number: Math.floor(x), decimal: x%1, index: i }));
const decimalSorted= [...rounded].sort((a,b)=> b.decimal-a.decimal);
const sum = rounded.reduce((pre, curr)=> pre + curr.number, 0) ;
const error= 100-sum;
for (let i = 0; i < error; i++) {
const element = decimalSorted[i];
element.number++;
}
const result= [...decimalSorted].sort((a,b)=> a.index-b.index);
return result.map(x=> x.number);
}
第四种情况
您只需要计算在每次汇总中为您的数字添加或减少了多少额外空气,然后在下一项中再次添加或减去它。
const v1 = [13.626332, 47.989636, 9.596008, 28.788024];// => [14, 48, 10, 28 ]
const v2 = [16.666, 16.666, 16.666, 16.666, 16.666, 16.666] // => [17, 16, 17, 16, 17, 17]
const v3 = [33.333, 33.333, 33.333] // => [33, 34, 33]
const v4 = [33.3, 33.3, 33.3, 0.1] // => [33, 34, 33, 0]
const normalizePercentageByWave= v4.reduce((pre, curr, i, arr) => {
let number = Math.round(curr + pre.decimal);
let total = pre.total + number;
const decimal = curr - number;
if (i == arr.length - 1 && total < 100) {
const diff = 100 - total;
total += diff;
number += diff;
}
return { total, numbers: [...pre.numbers, number], decimal };
}, { total: 0, numbers: [], decimal: 0 });