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

本文旨在提供一种配置化思路计算阶梯费用,更高级的做法则是通过数据库配置,注册中心等;在表达式上可以采用自定义或者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("[\\+\\-\\*/]", "");// 1switch (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.mzph.cn/news/34648.shtml

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

相关文章

Spring Boot 项目应用消息服务器RabbitMQ(简单介绍)

一、背景 本章讲述的是在用户下单环节&#xff0c;消息服务器RabbitMQ 的应用 1.1 消息服务器的应用 在写一个电商项目的小demo&#xff0c;在电商项目中&#xff0c;消息服务器的应用&#xff1a; 1、订单状态通知&#xff1a;当用户下单、支付成功、订单发货、订单完成等…

【MFC】10.MFC六大机制:RTTI(运行时类型识别),动态创建机制,窗口切分,子类化-笔记

运行时类信息&#xff08;RTTI&#xff09; C: ##是拼接 #是替换成字符串 // RTTI.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include <iostream> #include <afxwin.h>#ifdef _DEBUG #define new DEBUG_NEW #endifCWinApp th…

六种不同的CRM系统类型分别有哪些特点?

企业想要管理销售&#xff0c;可以选择CRM系统&#xff1b;企业想要优化业务流程&#xff0c;可以选择CRM系统&#xff1b;企业想要提高收入&#xff0c;可以选择CRM系统。下面来说说&#xff0c;CRM是什么&#xff1f;六种常见CRM系统类型对比。 什么是CRM&#xff1f; CRM是…

优秀的 Modbus 从站(从机、服务端)仿真器、串口调试工具

文章目录 优秀的 Modbus 从站&#xff08;从机、服务端&#xff09;仿真器、串口调试工具主要功能软件截图 优秀的 Modbus 从站&#xff08;从机、服务端&#xff09;仿真器、串口调试工具 官网下载地址&#xff1a;http://www.redisant.cn/mse 主要功能 支持多种Modbus协议…

Java课题笔记~ Spring 集成 MyBatis

Spring 集成 MyBatis 将 MyBatis 与 Spring 进行整合&#xff0c;主要解决的问题就是将 SqlSessionFactory 对象交由 Spring 来管理。所以该整合&#xff0c;只需要将 SqlSessionFactory 的对象生成器SqlSessionFactoryBean 注册在 Spring 容器中&#xff0c;再将其注入给 Dao…

多目标优化算法之樽海鞘算法(MSSA)

樽海鞘算法的主要灵感是樽海鞘在海洋中航行和觅食时的群聚行为。相关文献表示&#xff0c;多目标优化之樽海鞘算法的结果表明&#xff0c;该算法可以逼近帕雷托最优解&#xff0c;收敛性和覆盖率高。 通过给SSA算法配备一个食物来源库来解决第一个问题。该存储库维护了到目前为…

Docker镜像查看下载删除镜像文件的相关命令

1.镜像相关命令 本地查看有哪些镜像文件&#xff1a; docker images镜像的名称就是我们常见的一些软件&#xff0c;镜像相当于把软件和软件所需要的运行环境打包到一个镜像文件里面&#xff0c;将来在通过这个镜像文件创建出对应的容器&#xff0c;容器有了以后这些软件自动的…

java线程的优先级、守护线程的概念

1.线程的调度 抢占式调度 非抢占式调度 1.1 抢占式调度 优先级越高&#xff0c;抢到cpu的概率越高 1.2 守护线程 守护线程&#xff0c;非守护线程。当其他的非守护线程执行完毕以后&#xff0c;守护线程会陆续结束。 守护线程的应用场景

插入排序(Java实例代码)

目录 插入排序 一、概念及其介绍 二、适用说明 三、过程图示 四、Java 实例代码 InsertionSort.java 文件代码&#xff1a; 插入排序 一、概念及其介绍 插入排序(InsertionSort)&#xff0c;一般也被称为直接插入排序。 对于少量元素的排序&#xff0c;它是一个有效的算…

CNN(四):ResNet与DenseNet结合--DPN

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊|接辅导、项目定制 前面实现了ResNet和DenseNet的算法&#xff0c;了解了它们有各自的特点&#xff1a; ResNet&#xff1a;通过建立前面层与后面层之间的“短路…

TSINGSEE青犀视频安防监控视频平台EasyCVR设备在线,视频无法播放的原因排查

可支持国标GB28181、RTMP、RTSP/Onvif、海康Ehome、海康SDK、大华SDK、宇视SDK等多种协议接入的安防监控视频平台EasyCVR基于云边端一体化架构&#xff0c;具有强大的数据接入、处理及分发能力&#xff0c;可在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、…

IDEA全局设置MyBatis中写SQL语句提示

第一步&#xff1a;把这两个设置改成MySQL即可&#xff1a; 第二步&#xff1a;找到设置>编辑器>语言注入>店家加号&#xff0c;选择MySQL

微信小程序在使用vant组件库时构建npm报错

在跟着vant官方进行使用步骤一步步操作时&#xff0c;由于要构建NPM&#xff0c;但NPM包在App配置文件的外部 所以在做下图这一步时&#xff1a; 接着再进行npm构建时会报错 message:发生错误 Error: F:\前端学习\前端框架\小程序\project\demo\miniprogram解决方法 &#xf…

Java:正则表达式书写规则及相关案例:检验QQ号码,校验手机号码,邮箱格式,当前时间

正则表达式 目标:体验一下使用正则表达式来校验数据格式的合法性。需求:校验QQ号码是否正确&#xff0c;要求全部是数字&#xff0c;长度是(6-20&#xff09;之间&#xff0c;不能以0开头 首先用自己编写的程序判断QQ号码是否正确 public static void main(String[] args) {Sy…

递归、搜索与回溯算法

一.递归 &#xff08;1&#xff09;汉诺塔问题 当n2时&#xff0c;要将A中最下面盘子上方的盘子放到B上&#xff0c;最下面盘子放到C上&#xff0c;再将B上的盘子通过A放到C即可&#xff1b; 当n3时&#xff0c;要将A中最下面盘子上方的盘子放到B上&#xff0c;最下面盘子放到…

uniapp 小兔鲜儿 - 首页模块(1)

目录 自定义导航栏 静态结构 安全区域​ 通用轮播组件 静态结构 自动导入全局组件 全局组件类型声明 .d.ts文件 注册组件 vue/runtime-core 首页 – 轮播图指示点 首页 – 获取轮播图数据 首页 – 轮播图数据类型并渲染 首页 – 轮播图总结 首页分类 首页 – 前…

Jupyter Notebook 遇上 NebulaGraph,可视化探索图数据库

在之前的《手把手教你用 NebulaGraph AI 全家桶跑图算法》中&#xff0c;除了介绍了 ngai 这个小工具之外&#xff0c;还提到了一件事有了 Jupyter Notebook 插件: https://github.com/wey-gu/ipython-ngql&#xff0c;可以更便捷地操作 NebulaGraph。 本文就手把手教你咋在 J…

计算机网络核心-数据交换

1 概述 计算机网络的核心即数据交换。通过数据交换将数据从源主机发送到目的主机。 2 为什么需要数据交换 如果不是数据交换的方式&#xff0c;而是每两台主机直接连接&#xff0c;则会产生N^2链路问题。 即&#xff0c;假设有N台主机&#xff0c;两两间建立连接&#xff0c…

verilog学习笔记5——进制和码制、原码/反码/补码

文章目录 前言一、进制转换1、十进制转二进制2、二进制转十进制3、二进制乘除法 二、原码、反码、补码1、由补码计算十进制数2、计算某个负数的补码 前言 2023.8.13 天气晴 一、进制转换 1、十进制转二进制 整数&#xff1a;除以2&#xff0c;余数倒着写 小数&#xff1a;乘…

QT信号与槽的理解

文章目录 信号与槽的理解 信号与槽的理解 信号就是事件&#xff0c;比如button被点击的事件&#xff0c;ComboBox选项改变的事件&#xff0c;都是信号槽就是对信号进行响应的函数&#xff0c;可以是任意自定义函数一个信号可以对应多个槽多个信号可以对应一个槽信号的参数不能…