一个金额分摊的算法,将折扣分摊按比例(细单实收在总体的占比)到各个细单中。
此算法需要达到以下要求:
- 折扣金额接近细单总额,甚至折扣金额等于细单金额,某些时候甚至超过细单总额,要保证实收不为负数。
- 复杂度O(n)
…
写这个算法的初衷,就是因为现在网上的分摊算法,都没有考虑到最后一项不够减、只循环一次、折扣金额接近总额…
用例:
细单1:8.91
细单2:21.09
细单3:0.01
三个细单总和是 30.01
折扣金额:30
按比例分摊后,应该只有一项是 0.01
废话不多,直接上代码:
细单对象:
/**
* 细单类
*/
@Data
public static class Detail {
/**
* 用来标识记录
*/
private Long id;
/**
* 总额
*/
private BigDecimal money;
}
分摊算法:(忽略了金额从小到大排序,后续补上)
/**
* 分摊
*
* @param detailList 细单
* @param discountMoney 折扣
* @return 新的细单集合
*/
public static List<Detail> allocateDiscountMoney(List<Detail> detailList, BigDecimal discountMoney) {
// 分摊总金额
BigDecimal allocatedAmountTotal = discountMoney;
// 剩余分摊金额
BigDecimal leftAllocatedAmount = allocatedAmountTotal;
// 订单总实收
BigDecimal orderTotalAmount = detailList.stream().map(Detail::getMoney).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
// 结果集
List<Detail> resultList = new ArrayList<>();
for (int i = 0; i < detailList.size(); i++) {
// 结果
Detail resultDetail = new Detail();
BeanUtils.copyProperties(detailList.get(i), resultDetail);
BigDecimal money = resultDetail.getMoney();
// 占比比例=自身实收/实收总额
BigDecimal proportion = money.divide(orderTotalAmount, 10, RoundingMode

最低0.47元/天 解锁文章
8171

被折叠的 条评论
为什么被折叠?



