最大余额法解决百分比和不是100%的问题

1,641 阅读1分钟

场景

我们经常在画百分比图表时候,直接四舍五入会出现相加不等于100%,最大余额法解决百分比和不是100%的问题。

怎么保证所有占比之和等于100%

echarts的饼图的百度通过传入数据自动算出每个项在总数当中所占的比例大小,且保证所有的比率相加等于100%,那他是如何计算百分比的呢。通过阅读源码我们可以得知他使用最大余额法。

代码

let arr = [3, 3, 8];

let aPercentage = getPercentValue(arr, 0, 2);
let bPercentage = getPercentValue(arr, 1, 2);
let cPercentage = getPercentValue(arr, 2, 2);
let percentageSum = aPercentage + bPercentage + cPercentage;
console.log('get percentage', aPercentage, bPercentage, cPercentage, percentageSum);

//最大余额法解决百分比和不是100%的问题
function getPercentValue(arrList, index, precision) {
    if (!arrList[index]) {
        return 0;
    }
    if (!precision) precision = 2;
    let sum = arrList.reduce((acc, val) => {
        return acc + (isNaN(val) ? 0 : val);
    }, 0);
    if (sum === 0) {
        return 0;
    }
    let digits = Math.pow(10, precision);
    let votesPerQuota = arrList.map((val) => {
        return (isNaN(val) ? 0 : val) / sum * digits * 100;
    });

    let targetSeats = digits * 100;
    let seats = votesPerQuota.map((votes) => {
        return Math.floor(votes);
    });

    let currentSum = seats.reduce((acc, val) => {
        return acc + val;
    }, 0);
 
    let remainder = votesPerQuota.map(function (votes, index) {
        return votes - seats[index];
    });
   
    while (currentSum < targetSeats) {
        let max = Number.NEGATIVE_INFINITY;
        let maxId = null;
        for (let i = 0, len = remainder.length; i < len; ++i) {
            if (remainder[i] > max) {
                max = remainder[i];
                maxId = i;
            }
        }
        ++seats[maxId];
        remainder[maxId] = 0;
        ++currentSum;
    }

    return seats[index] / digits;
}