阶梯费用计算(配置化_最小demo)

news2025/1/11 16:54:27

本文旨在提供一种配置化思路计算阶梯费用,更高级的做法则是通过数据库配置,注册中心等;在表达式上可以采用自定义或者spel表达式等其他方式进行处理;(代码仅展示最小demo,部分不完善地方自行补充)

思路:N个区间对应N个费用模式(费用模式可以根据需要进行扩展);

          先进行第一个区间的值,收集后续区间,然后按照最大区间差值加权

          

目录

一、核心代码

二、工具类DataCompareUtils


一、核心代码



import java.math.BigDecimal;
import java.math.MathContext;
import java.util.ArrayList;
import java.util.List;

/**
 * description:
 */
public class FeeT {
    public static void main(String[] args) {
        /**
         * 如果 value落在区间N,
         *     当前区间则为当前值减去最小值 加权计算
         *     剩余区间则按照区间最大值  加权计算,
         *   1  10 80 -1
         */
        String expression = "(0,10]#(10,20]#(20,100]#(100,";
        String model = "+1#*1#*1#-1";
        String value = "101";
        BigDecimal bigDecimal = getStepFeeItem(expression, model, value);
        System.out.println(bigDecimal.doubleValue());


    }

    private static BigDecimal getStepFeeItem(String expression, String model, String value) {
        BigDecimal bigDecimal = new BigDecimal(0);
        String[] expressionArr = expression.split("#");
        String[] modelArr = model.split("#");
        List<String> expressionA = new ArrayList<>();
        /**
         * 计算第一个区间的值
         */
        bigDecimal = computeFirst(value, bigDecimal, expressionArr, modelArr, expressionA);
        bigDecimal = computeLast(bigDecimal, expressionA);
        return bigDecimal;
    }

    private static BigDecimal computeLast(BigDecimal bigDecimal, List<String> expressionA) {
        for (String s : expressionA) {
            String[] split = s.split("#");
            BigDecimal computeValue = computeValue(BigDecimal.valueOf(Double.parseDouble(maxRange(split[1]))).subtract(BigDecimal.valueOf(Double.parseDouble(minRange(split[1])))), split[0], true);
            bigDecimal = bigDecimal.add(computeValue);
        }
        return bigDecimal;
    }

    private static BigDecimal computeFirst(String value, BigDecimal bigDecimal, String[] expressionArr, String[] modelArr, List<String> expressionA) {
        for (int i = expressionArr.length - 1; i >= 0; i--) {
            if (DataCompareUtils.checkValue(value, expressionArr[i])) {
                BigDecimal computeValue = computeValue(BigDecimal.valueOf(Double.parseDouble(value)).subtract(BigDecimal.valueOf(Double.parseDouble(minRange(expressionArr[i])))), modelArr[i], true);
                bigDecimal = bigDecimal.add(computeValue);
                //如果目标值在遍历区间,则剩余区间则放到另外一个队列中
                for (int j = i - 1; j >= 0; j--) {
                    expressionA.add(new StringBuilder().append(modelArr[j]).append("#").append(expressionArr[j]).toString());
                }
                break;
            }
        }
        return bigDecimal;
    }


    public static String minRange(String expression) {
        String all = expression.replaceAll("[^0-9.,]", "");
        String[] split = all.split(",");
        return split[0];
    }

    public static String maxRange(String expression) {
        String all = expression.replaceAll("[^0-9.,]", "");
        String[] split = all.split(",");
        return split[1];
    }

    public static BigDecimal computeValue(BigDecimal value, String expression, boolean flag) {
        String symbol = expression.replaceAll("[^\\+\\-\\*/]", ""); //+-*/
        String feeValue = expression.replaceAll("[\\+\\-\\*/]", "");// 1
        switch (symbol) {
            case "+":
                return flag ? BigDecimal.valueOf(Double.parseDouble(feeValue)).setScale(4, BigDecimal.ROUND_CEILING) : value.add(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);
            case "-":
                return flag ?BigDecimal.valueOf(Double.parseDouble(feeValue)).multiply(BigDecimal.valueOf(-1)).setScale(4, BigDecimal.ROUND_CEILING): value.subtract(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);
            case "*":
                return value.multiply(BigDecimal.valueOf(Double.parseDouble(feeValue))).setScale(4, BigDecimal.ROUND_CEILING);
            case "/":
                return value.divide(BigDecimal.valueOf(Double.parseDouble(feeValue)), MathContext.DECIMAL64).setScale(4, BigDecimal.ROUND_CEILING);
            default:
                return value;
        }
    }

}

二、工具类DataCompareUtils

数据比较工具,不同区间的值进行比较


import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
 * description: 数据比较工具类
 */
public class DataCompareUtils {
    private DataCompareUtils() {
    }


    public static final Map<String, String> SYMBOL_MAP = new HashMap<>();

    static {
        SYMBOL_MAP.put("(,)", "(,)");
        SYMBOL_MAP.put("[,)", "[,)");
        SYMBOL_MAP.put("(,]", "(,]");
        SYMBOL_MAP.put("[,]", "[,]");
        SYMBOL_MAP.put("[,", "[,");
        SYMBOL_MAP.put("(,", "(,");
        SYMBOL_MAP.put(",]", ",]");
        SYMBOL_MAP.put(",)", ",)");
    }

    public static final String SYMBOL_01 = "(,)";
    public static final String SYMBOL_02 = "[,)";
    public static final String SYMBOL_03 = "(,]";
    public static final String SYMBOL_04 = "[,]";
    public static final String SYMBOL_05 = "[,";
    public static final String SYMBOL_06 = "(,";
    public static final String SYMBOL_07 = ",]";
    public static final String SYMBOL_08 = ",)";

    private static final Pattern NUMBER_REG = Pattern.compile("^-?\\d+(\\.\\d+)?$");

    /**
     * 双边校验 返回true说明不符合
     * [4,5] (3,5)
     * 不符合返回false,符合区间返回true
     *
     * @param value
     * @return
     */

    public static boolean checkValue(String value, String config) {
        if (StringUtils.isEmpty(config)) {
            return false;
        }
        config = config.replace(" ", "").replace(",", ",").replace("(", "(").replace("【", "[").replace("】", "]").replace(")", ")").trim();
        config = config.replaceAll("[^0-9.()\\[\\],]", ""); //获取 [3,8]
        String s = config.replaceAll("[^\\[\\]\\(\\),]", "");//获取 []
        if (StringUtils.isEmpty(SYMBOL_MAP.get(s))) {
            return false;
        }
        /**
         * 第一个为值  第二个为配置表达式
         */

        boolean flag = false;
        switch (s) {
            case SYMBOL_01:
                flag = checkLeftNoAndRightNo(value, config);
                break;
            case SYMBOL_02:
                flag = checkLeftAndRightNo(value, config);
                break;
            case SYMBOL_03:
                flag = checkLeftNoAndRight(value, config);
                break;
            case SYMBOL_04:
                flag = checkLeftAndRight(value, config);
                break;
            case SYMBOL_05:
                flag = checkLeft(value, config);
                break;
            case SYMBOL_06:
                flag = checkLeftNo(value, config);
                break;
            case SYMBOL_07:
                flag = checkRight(value, config);
                break;
            case SYMBOL_08:
                flag = checkRightNo(value, config);
                break;
            default:
                break;
        }
        return flag;
    }

    //(5,8)
    public static boolean checkLeftNoAndRightNo(String value, String config) {
        String range = config.replace("(", "").replace(")", "");
        String[] split = range.split(",");
        return checkNoIncludeMin(value, split[0]) && checkNoIncludeMax(value, split[1]);
    }

    //(5,8]
    public static boolean checkLeftNoAndRight(String value, String config) {
        String range = config.replace("(", "").replace("]", "");
        String[] split = range.split(",");
        return checkNoIncludeMin(value, split[0]) && checkIncludeMax(value, split[1]);
    }

    //[5,8)
    public static boolean checkLeftAndRightNo(String value, String config) {
        String range = config.replace("[", "").replace(")", "");
        String[] split = range.split(",");
        return checkIncludeMin(value, split[0]) && checkNoIncludeMax(value, split[1]);
    }

    //[5,8]
    public static boolean checkLeftAndRight(String value, String config) {
        String range = config.replace("[", "").replace("]", "");
        String[] split = range.split(",");
        return checkIncludeMin(value, split[0]) && checkIncludeMax(value, split[1]);
    }

    //(5,
    public static boolean checkLeftNo(String value, String config) {
        String range = config.replace("(", "").replace(",", "");
        return checkNoIncludeMin(value, range);
    }

    //[5,
    public static boolean checkLeft(String value, String config) {
        String range = config.replace("[", "").replace(",", "");
        return checkIncludeMin(value, range);
    }

    //,8)
    public static boolean checkRightNo(String value, String config) {
        String range = config.replace(")", "").replace(",", "");
        return checkNoIncludeMax(value, range);
    }

    //,8]
    public static boolean checkRight(String value, String config) {
        String range = config.replace("]", "").replace(",", "");
        return checkIncludeMax(value, range);
    }


    /**
     * 校验下限 不含 (6,
     *
     * @param value
     * @param target
     * @return
     */
    public static boolean checkNoIncludeMin(String value, String target) {
        if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {
            return false;
        }
        if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) > 0) {
            return true;
        }
        return false;
    }

    /**
     * 含最小 [6,
     *
     * @param value
     * @param target
     * @return
     */
    public static boolean checkIncludeMin(String value, String target) {
        if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {
            return false;
        }
        if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) >= 0) {
            return true;
        }
        return false;
    }

    /**
     * 最大包含  ,6]
     *
     * @param value
     * @param target
     * @return
     */
    public static boolean checkIncludeMax(String value, String target) {
        if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {
            return false;
        }
        if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 不含最大校验    ,6)
     *
     * @param value
     * @param target
     * @return
     */
    public static boolean checkNoIncludeMax(String value, String target) {
        if (StringUtils.isEmpty(value) || StringUtils.isEmpty(target)) {
            return false;
        }
        if (BigDecimal.valueOf(Double.parseDouble(value)).compareTo(BigDecimal.valueOf(Double.parseDouble(target))) < 0) {
            return true;
        }
        return false;
    }

    /**
     * 判断是否为数字
     *
     * @param value
     * @return
     */
    public static boolean checkIsNumber(String value) {
        return NUMBER_REG.matcher(value).matches();
    }

    //\u00A0,\u0020,\u3000
//    1.不间断空格\u00A0,主要用在office中,让一个单词在结尾处不会换行显示,快捷键ctrl+shift+space ;
//2.半角空格(英文符号)\u0020,代码中常用的;
//3.全角空格(中文符号)\u3000,中文文章中使用;
    public static String replaceSpecialEmpty(String value) {
        if (StringUtils.isEmpty(value)) {
            return value;
        }
        return value.replace("\\u00A0", "").replace("\\u0020", "").replace("\\u3000", "");
    }


    public static void main(String[] args) {

        List<String> arrayList = new ArrayList<>();
        arrayList.add("(5,8)");
        arrayList.add("[5,8)");
        arrayList.add("(5,8]");
        arrayList.add("[5,8]");
        arrayList.add("[5,");
        arrayList.add("(5,");
        arrayList.add(",8]");
        arrayList.add(",8)");
        String target = "8.01";
        for (String s : arrayList) {
            boolean checked = checkValue(target, s);
            System.out.printf("s:%s ,%s, %s", s, target, checked);
            System.out.println();
        }

    }

}

三、效果

String expression = "(0,10]#(10,20]#(20,100]#(100,";
String model = "*1#*2#*2#+1";
String value = "101";

1+80*2+10*2+10

1+160+20+10=191

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/870756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

重置mariadb数据库密码

使用场景重置步骤 重置数据库root用户密码为空重置数据库密码 文档暂时只支持未开启ha时manager使用的mariadb&#xff0c;开启ha的txsql和kundb类似&#xff0c;my.cnf文件地址和登录数据库命令不同 使用场景 manager数据库密码是通过调用接口并根据db.properties文件获取的…

众和转债,宏微转债,阳谷转债上市价格预测

众和转债 基本信息 转债名称&#xff1a;众和转债&#xff0c;评级&#xff1a;AA&#xff0c;发行规模&#xff1a;13.75亿元。 正股名称&#xff1a;新疆众和&#xff0c;今日收盘价&#xff1a;8.14元&#xff0c;转股价格&#xff1a;8.2元。 当前转股价值 转债面值 / 转股…

基于SqlSugar的开发框架循序渐进介绍-- 快速构建系统参数管理界面

在参照一些行业系统软件的时候&#xff0c;发现一个做的挺不错的系统功能-系统参数管理&#xff0c;相当于把任何一个基础的系统参数碎片化进行管理&#xff0c;每次可以读取一个值进行管理&#xff0c;这样有利于我们快速的处理业务需求&#xff0c;是一个挺好的功能。本篇随笔…

【FastColoredTextBox】C# 开源文本编辑控件

主界面截图 使用Demos演示 FastColoredTextBox 是一个用于在 C# 程序中实现高亮语法着色、代码编辑和文本显示的自定义控件。它提供了许多功能&#xff0c;包括&#xff1a; 语法高亮&#xff1a;FastColoredTextBox 支持多种语言的语法高亮&#xff0c;可以根据语法规则将不同…

Linux 终端操作命令(2)内部命令

Linux 终端操作命令 也称Shell命令&#xff0c;是用户与操作系统内核进行交互的命令解释器&#xff0c;它接收用户输入的命令并将其传递给操作系统进行执行&#xff0c;可分为内部命令和外部命令。内部命令是Shell程序的一部分&#xff0c;而外部命令是独立于Shell的可执行程序…

32 | 全球新冠肺炎确诊病例趋势分析

任务背景 过去一年多的时间,对我们影响最大的事件就是全球新冠肺炎的大流行。新冠肺炎除了对患者带来痛苦之外,对医疗系统也带来了巨大的挑战。许多患者陷入危险的本质原因就是医疗资源的紧张,如果可以根据现有确诊的数据来预测将来可能的确诊数,那政府和医院就能够提前对…

【python可视化】爬取豆瓣电影Top250(附源码)

前言 在网络爬虫的开发过程中&#xff0c;经常会遇到需要处理一些反爬机制的情况。其中之一就是网站对于频繁访问的限制&#xff0c;即IP封禁。为了绕过这种限制&#xff0c;我们可以使用代理IP来动态改变请求的来源IP地址。在本篇博客中&#xff0c;将介绍如何使用代理IP的技术…

【第二阶段】在函数中定义参数是函数的函数

1.理解&#xff1a;在一个函数中有一个参数a,这个参数a又属于一个函数&#xff0c;a即时参数又是函数 2.用kotlin实现登录 /*** You can edit, run, and share this code.* play.kotlinlang.org*/ fun main() {//调用传参//普通参数传入即可,针对在调用函数中的参数函数传入使用…

Leetcode34 在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums&#xff0c;和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target&#xff0c;返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 代码&#xff1a; c…

SpringBoot第35讲:SpringBoot集成连接池 - 默认连接池HikariCP

SpringBoot第35讲&#xff1a;SpringBoot集成连接池 - 默认连接池HikariCP 本文是SpringBoot第35讲&#xff0c;主要介绍数据库连接池&#xff0c;以及SpringBoot集成默认的HikariCP的实践。 文章目录 SpringBoot第35讲&#xff1a;SpringBoot集成连接池 - 默认连接池HikariCP1…

【STM32】简介

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2022博客之星T…

Exploiting Proximity-Aware Tasks for Embodied Social Navigation 论文阅读

论文信息 题目&#xff1a;Exploiting Proximity-Aware Tasks for Embodied Social Navigation 作者&#xff1a;Enrico Cancelli&#xff0c; Tommaso Campari 来源&#xff1a;arXiv 时间&#xff1a;2023 Abstract 学习如何在封闭且空间受限的室内环境中在人类之间导航&a…

StarGANv2: Diverse Image Synthesis for Multiple Domains论文解读及实现

StarGAN v2: Diverse Image Synthesis for Multiple Domainsp github:https://github.com/clovaai/stargan-v2 0 小结 0.1 模型 4个 模型四个&#xff1a; Generator&#xff1a; G网络 输入图片x&#xff0c;和风格编码s&#xff08;可以是F网络或者E网络生成的s&#xff…

LeetCode 778. Swim in Rising Water【最小瓶颈路;二分+BFS或DFS;计数排序+并查集;最小生成树】2096

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

城市最短路

题目描述 下图表示的是从城市A到城市H的交通图。从图中可以看出&#xff0c;从城市A到城市H要经过若干个城市。现要找出一条经过城市最少的一条路线。 输入输出格式 输入格式&#xff1a; 无 输出格式&#xff1a; 倒序输出经过城市最少的一条路线 输入输出样例 输入样例…

【LeetCode75】第二十七题(933)最近的请求次数

目录 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 代码运行结果&#xff1a; 题目&#xff1a; 示例&#xff1a; 分析&#xff1a; 首先这是LeetCode75里第一道设计类的题目&#xff0c;这种类型的题目会比较新颖&#xff0c;就是按照题目要求来设计一个类。然后…

GIL 锁或将在 CPython 中成为可选项

哈喽大家好&#xff0c;我是咸鱼 几天前有媒体报道称&#xff0c;经过多次辩论&#xff0c;Python 指导委员会打算批准通过 PEP 703 提案&#xff0c;让 GIL&#xff08;全局解释器&#xff09;锁在 CPython 中成为一个可选项 PEP 703 提案主要目标是使 GIL 变成可选项&#…

二叉树的讲解

&#x1f493;博主个人主页:不是笨小孩&#x1f440; ⏩专栏分类:数据结构与算法&#x1f440; 刷题专栏&#x1f440; C语言&#x1f440; &#x1f69a;代码仓库:笨小孩的代码库&#x1f440; ⏩社区&#xff1a;不是笨小孩&#x1f440; &#x1f339;欢迎大家三连关注&…

定义行业新标准?谷歌:折叠屏手机可承受20万次折叠

根据Patreon账户上的消息&#xff0c;Android专家Mishaal Rahman透露&#xff0c;谷歌计划推出新的硬件质量标准&#xff0c;以满足可折叠手机市场的需求。Android原始设备制造商&#xff08;OEM&#xff09;将需要完成谷歌提供的问卷调查&#xff0c;并提交样品设备进行严格审…

读书笔记 |【项目思维与管理】➾ 顺势而动

读书笔记 |【项目思维与管理】➾ 顺势而动 一、企业步入“终结者时代”二、过去成功的经验也许是最可怕的三、做好非重复性的事四、适应客户是出发点五、向知识型企业转变六、速度是决胜条件 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; …