栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVA计算饼图百分比合计不是100的问题处理,最大余额法

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA计算饼图百分比合计不是100的问题处理,最大余额法

背景:

由于各种原因需要后端来计算每个项所占的百分比,但是会发现计算的各项百分比合计不绝对是100,不能简单的对各项使用四舍五入法,舍九法,进一法等。

思路:

使用最大余额法(比例代表制投票制度下,一种议席分配的方法,结尾有描述)

举个具体例子就很好理解:总计29个员工给3个组投票,请计算出各组所占的百分比,精确到整数。

常规计算出百分比如下:

组名票数计算值(%)精确到整数小数余额
A组1034.482.....340.482.....
B组1241.379.....410.379.....
C组724.137.....240.137.....

但是很明显,计算值存在小数,产品经理要求精确到整数,且最终的百分比合计又需要等于100,还剩下最后一个数分给谁?

按照最大余额法,应该将最后一个数分给小数余额最大的A组(0.482.....)。同理,如果多出两个数,第二多出的数应该分给小数余额第二大的组。

使用java编码实现如下:

为了方便观察,封装了实体类:

@Data
@NoArgsConstructor
public class PercentVo {
    
    private int number;
    
    private int percent;
    
    @JSONField(serialize = false)
    private Double point;
    
    private String name;

    public PercentVo(int number, String name) {
        this.number = number;
        this.name = name;
    }
}

方法及测试类:

public class NumberUtils {

    
    public static void calculatePercent(List list) {
        //求和:总票数
        int sum = list.stream().mapToInt(PercentVo::getNumber).sum();
        for (PercentVo percentVo : list) {
            double value = percentVo.getNumber() * 100 / (double) sum;
            int valueInt = (int) value;
            //设置对应的百分比
            percentVo.setPercent(valueInt);
            //获取小数点后的值
            percentVo.setPoint(value - valueInt);
            System.out.println("percentVo = " + percentVo);
        }
        //求和:当前各项百分比合计。由于我们舍弃了小数位,所以该合计只会小于等于100
        int curSum = list.stream().mapToInt(PercentVo::getPercent).sum();
        while (curSum < 100) {
            //找出小数余额最大的组,对其进行加1
            PercentVo max = list.stream().max(Comparator.comparingDouble(PercentVo::getPoint)).get();
            max.setPercent(max.getPercent() + 1);
            //当前这个数已经加1了,不应该参与下一轮的竞选
            max.setPoint(0.0);
            curSum++;
        }
    }

    public static void main(String[] args) {
        PercentVo v1 = new PercentVo(10, "A组");
        PercentVo v2 = new PercentVo(12, "B组");
        PercentVo v3 = new PercentVo(7, "C组");
        List list = Arrays.asList(v1, v2, v3);
        System.out.println("处理前--------------------------");
        calculatePercent(list);
        System.out.println("处理后--------------------------");
        for (PercentVo percentVo : list) {
            System.out.println(percentVo);
        }
    }
}

结果打印如下:

处理前--------------------------
percentVo = PercentVo(number=10, percent=34, point=0.48275862068965836, name=A组)
percentVo = PercentVo(number=12, percent=41, point=0.3793103448275872, name=B组)
percentVo = PercentVo(number=7, percent=24, point=0.137931034482758, name=C组)
处理后--------------------------
PercentVo(number=10, percent=35, point=0.0, name=A组)
PercentVo(number=12, percent=41, point=0.3793103448275872, name=B组)
PercentVo(number=7, percent=24, point=0.137931034482758, name=C组)

扩展:这里为了方便,仅做了精确到整数,还可以扩展为:添加入参2,自定义精度。来提高适用性,思路是一样的。

延申:

最大余额方法(英文:Largest Remainder Method)又称数额制,是比例代表制投票制度下,一种议席分配的方法,相对于最高均数方法。

透过最大余额方法,候选人须以名单参选,每份名单的人数最多可达至相关选区内的议席数目。候选人在名单内按优先次序排列。选民投票给一份名单,而不是个别候选人。投票结束后,把有效选票除以数额。一份名单每取得数额1倍的票数,便能获分配一个议席。每份名单的候选人按原先订立的顺序当选。

如此类推、将议席分配至每份名单的余额,均比数额为低的时候,则从最大余额者顺序分配余下议席;最大余额方法因而得名。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/919920.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号