数据百分比表示函数

94 阅读1分钟

示例

[3, 3, 8] => ["21%", "21%", "58%"]
[{label: "test1",value: 2}, {label: 'tes2', value: 4}] => [{label: "test1",value: 2, percentValue: '33%'}, {label: 'tes2', value: 4, percentValue: '67%'}]

场景

画百分比图表时,需要将原始值转化为相应百分比形式展示。

关键问题

如何保证百分比总和为100%?

比如: [3, 3, 8]直接使用toFixed四舍五入取整 => [21, 21, 57],和为99,不是100;

解决方案:使用最大余额法进行进位确保百分比和为100%;

核心源码:

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;
}

链接:juejin.cn/post/694644… // 不是本文的源码

当出现[3,3,3]情况,上述方法将直接进位为[34%,33%,33%],未保证相同值均分

比如:[3,3,3] 应=> [33%,33%,33%] // 不进位

解决方案:

// 对余数出现次数进行计数
const repeatRemainders: Record<string, K> = remainders.reduce(
    (pre, cur, idx) => {
      pre[cur] = {
        time: (pre[cur]?.time || 0) + 1,
        idxArr: (pre[cur]?.idxArr || []).concat(idx),
        value: cur
      };
      return pre;
    },
    {}
);
​
// 降序排序
const sortedRepeatRemainders: K[] = sortArray(
    Object.values(repeatRemainders),
    {
      field: 'value',
      order: 'desc',
    }
);
​
let currentSum: number = seats.reduce((pre, cur) => pre + cur);
sortedRepeatRemainders.forEach((item) => {
    // 保证相同值同加同减
    if (currentSum + item.time <= targetSeats) {
      item.idxArr.forEach((idx) => seats[idx]++);
      currentSum += item.time;
    }
});

源码

code.juejin.cn/pen/7395126…