json字符串转为开闭区间
1.需求背景
1.1 前端页面展示

1.2 前后端约定交互json
按照页面每一行的从左到右
* 示例
[{"leftSymbol":">=","leftNum":100,"relation":"无","rightSymbol":null,"rightNum":0},
{"leftSymbol":"<","leftNum":1000,"relation":"且","rightSymbol":">","rightNum":3}]
1.3最终传到数据采集,想要的结果
* 转换为 [100,1000);[1000,+无穷);(-无穷,100]
1.4 json转为开闭区间
这是很重要的一步,过程太长,在第二大点里边说
1.5转为开闭区间后,查缺补漏
除了要把json转为开闭区间外,还要考虑多种情况
1.比如上边的例子,用户只选择了 [100,1000)
但是我需要补齐 [100,1000);[1000,+无穷);(-无穷,100]
2.如果用户选择了不连续区间,我还要把中断的部分补齐
比如用户选择了[-无穷,100];(300,正无穷)
但是我需要返回[-无穷,100];(100,300];(300,正无穷)
3.还有比如第二点和第三点情况都存在的情况
用户选择了[1,100];[500,1000]
但是我需要返回(-无穷,1);(100,500);(1000,+无穷)
2.json转换为开闭区间
思路:
根据页面上用户可能发生的操作行为,假定他是正确的前提下
(比如他没有选择空区间 如<1 且 >2,或者他没有选择重复区间 比如第一行 >1 第二行又>2)
* 逻辑解析: * //1.第一种大的情况 左边是( [ * //1.1 左边是( [ relation是“无” * //1.2 左边是 ( [ relation是“且” * //1.3 左边是 ( [ relation是“或” * //2.第二种大情况 左边是 ) ] * //2.1 左边是 ) ] relation是“无” * //2.2 左边是 ) ] relation是“且” * //2.3 左边是 ) ] relation是“或”
3.根据类型取最大值最小值
Integer Double Float Long 都有各自的MAX_VALUE 和 MIN_VALUE
比如 Long.MIN_VALUE Long.MAX_VALUE
这段代码比较垃圾 我还没有优化
因为Integer Double Float Long
有共同点
extends Number implements Comparable
其实可以从这一点入手 然后用泛型 整合成一个方法
4.查缺补漏
json转换为开闭区间之后
1.补充MAX和MIN
要和各自区间的最大值最小值比
如果已有区间的元素中最小值,比这个类型的最小值大,说明要补充区间
比如现在类型是Integer,区间最小值100,那就需要补充区间(Integer.MIN_VALUE,100)
具体100是开是闭,看具体情况
2.补充中断区间
再映射为list实体,然后用java8排序(这是一个比较重要的思想,以后应该也会用到)
第一个数排序一致,就用第二个数排序
按照从大到小的顺序,每个元素的开头的值和上一个元素结尾的值做比较,不相等,就是有漏的,就在这添加一个区间,
至于区间的开闭,需要看上一个区间的右区间和下一个区间的左区间,取相反
比如上个区间(100,200) 下个区间是[300,500)
那补充过来的这个区间就是[200,300)
5.上代码
思路大致如上,直接上代码,注释写的挺清楚的
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;/*** @Description: 分区设置 区间接收传输实体* @Version 1.0*/
@ApiModel("分区设置 区间接收传输实体")
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
@Builder
public class Range<T> {@ApiModelProperty("第一个符号 > >= < <=")String leftSymbol;@ApiModelProperty("第一个数字")T leftNum;@ApiModelProperty("无 且 或")String relation;@ApiModelProperty("第二个符号 > >= < <=")String rightSymbol;@ApiModelProperty("第二个数字")T rightNum;public static void main(String[] args) throws JsonProcessingException {Range one = Range.builder().leftSymbol(">=").leftNum(1).relation("且").rightSymbol("<").rightNum(100).build();Range two = Range.builder().leftSymbol(">=").leftNum(100).relation("且").rightSymbol("<").rightNum(300).build();List<Range> list = Arrays.asList(one,two);//转json存到数据库ObjectMapper objectMapper = new ObjectMapper();String test = objectMapper.writeValueAsString(list);System.out.println(test);//从数据取出来json转ListList<Range> personList = objectMapper.readValue(test, new TypeReference<List<Range>>() {});System.out.println(personList.size());}/*** 通过符号取开闭区间** @param symbol* @return*/public String parseSymbol(String symbol) {if(StringUtils.isEmpty(symbol)){return null;}switch (symbol) {case ">":return LEFT_OPEN;case ">=":return LEFT_CLOSE;case "<":return RIGHT_OPEN;case "<=":return RIGHT_CLOSE;default:return null;}}public static final String LEFT_OPEN = "(";public static final String LEFT_CLOSE = "[";public static final String RIGHT_OPEN = ")";public static final String RIGHT_CLOSE = "]";// "(","["public static final List<String> left = Arrays.asList(">", ">=");// ")","]"public static final List<String> right = Arrays.asList("<", "<=");/*** relation的三种情况 无 且 或*/public static final String NOT_HAVE = "无";public static final String AND = "且";public static final String OR = "或";/*** 用法:返回值为转换后的开闭区间 含“或”时 则返回分号;拼接的两个区间* <p>* 逻辑解析:* //1.第一种大的情况 左边是( [* //1.1 左边是( [ relation是“无”* //1.2 左边是 ( [ relation是“且”* //1.3 左边是 ( [ relation是“或”* //2.第二种大情况 左边是 ) ]* //2.1 左边是 ) ] relation是“无”* //2.2 左边是 ) ] relation是“且”* //2.3 左边是 ) ] relation是“或”** @param dbFieldType* @return*/public String parse(DBFieldType dbFieldType) {if (Objects.isNull(dbFieldType)) {return null;}//1.第一种大的情况 左边是( [if (left.contains(this.leftSymbol)) {return returnLeft(dbFieldType);} else if (right.contains(this.leftSymbol)) {//2.第二种大情况 左边是 ) ]return returnRight(dbFieldType);}return null;}/*** //2.第二种大情况 左边是 ) ]* //2.1 左边是 ) ] relation是“无”* //2.2 左边是 ) ] relation是“且”* //2.3 左边是 ) ] relation是“或”** @param dbFieldType* @return*/private String returnRight(DBFieldType dbFieldType) {StringBuilder builder = new StringBuilder();//通过> >=取开闭区间符号String symbol = this.parseSymbol(this.leftSymbol);if (StringUtils.isEmpty(symbol)) {return null;}//取当前字段的最小值Object min = dbFieldType.getMin();//2.1 左边是 ) ] relation是“无”if (NOT_HAVE.equals(this.relation)) {builder.append(LEFT_OPEN).append(min).append(Constant.COMMA_SPLIT).append(this.leftNum).append(symbol);} else if (AND.equals(this.relation)) {//2.2 左边是 ) ] relation是“且”//假定表达式校验通过之后才能执行这个解析方法 如果左边是)] 那右边肯定是([String symbolRight = this.parseSymbol(this.rightSymbol);if (StringUtils.isEmpty(symbolRight)) {return null;}builder.append(symbolRight).append(rightNum).append(Constant.COMMA_SPLIT).append(this.leftNum).append(symbol);} else if (OR.equals(this.relation)) {//2.3 左边是 ) ] relation是“或”//分开两个区间返回//第一个区间builder.append(LEFT_OPEN).append(min).append(Constant.COMMA_SPLIT).append(this.leftNum).append(symbol);//第二个区间String builderRight = builderRight(dbFieldType);builder.append(Constant.SEMICOLON).append(builderRight);}return builder.toString();}/*** //1.第一种大的情况 左边是( [* //1.1 左边是( [ relation是“无”* //1.2 左边是 ( [ relation是“且”* //1.3 左边是 ( [ relation是“或”** @param dbFieldType* @return*/private String returnLeft(DBFieldType dbFieldType) {StringBuilder builder = new StringBuilder();//通过> >=取开闭区间符号String symbol = this.parseSymbol(this.leftSymbol);String symbolRight = this.parseSymbol(this.rightSymbol);if (StringUtils.isEmpty(symbol)) {return null;}//取当前字段类型的最大值Object max = dbFieldType.getMax();//1.1 左边是( [ relation是“无”if (NOT_HAVE.equals(this.relation)) {//取当前字段类型的最大值,开区间builder.append(symbol).append(this.leftNum).append(Constant.COMMA_SPLIT).append(max).append(RIGHT_OPEN);} else if (AND.equals(this.relation)) {//1.2 左边是 ( [ relation是“且”builder.append(symbol).append(this.leftNum).append(Constant.COMMA_SPLIT).append(this.rightNum).append(symbolRight);} else if (OR.equals(this.relation)) {//1.3 左边是 ( [ relation是“或”//分开两个区间返回//第一个区间builder.append(symbol).append(this.leftNum).append(Constant.COMMA_SPLIT).append(max).append(RIGHT_OPEN);//第二个区间String builderRight = builderRight(dbFieldType);builder.append(Constant.SEMICOLON).append(builderRight);}return builder.toString();}/*** 处理第二个区间** @param dbFieldType* @return*/public String builderRight(DBFieldType dbFieldType) {Object max = dbFieldType.getMax();//第二个区间StringBuilder builder2 = new StringBuilder();//通过> >=取开闭区间符号String symbol2 = this.parseSymbol(this.rightSymbol);if (StringUtils.isEmpty(symbol2)) {return null;}// 右边是 ( [if (left.contains(this.rightSymbol)) {builder2.append(symbol2).append(this.rightNum).append(Constant.COMMA_SPLIT).append(max).append(RIGHT_OPEN);} else if (right.contains(this.rightSymbol)) {//右边是 ) ]Object min = dbFieldType.getMin();builder2.append(LEFT_OPEN).append(min).append(Constant.COMMA_SPLIT).append(this.rightNum).append(symbol2);}return builder2.toString();}}
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.alibaba.nacos.common.utils.StringUtils;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;import java.util.*;
import java.util.function.Consumer;/*** @Description: 范围区间工具类* @Version 1.0*/
@Slf4j
public class RangeParseUtil {/*** * 通过json串转开闭区间* * 入参是json和字段类型* * 返回是分号;隔开的开闭区间* * 示例 [{"leftSymbol":">=","leftNum":100,"relation":"无","rightSymbol":null,"rightNum":0},{"leftSymbol":"<","leftNum":1000,"relation":"且","rightSymbol":">","rightNum":3}]* * 转换为 [100,1000)** @param rangeSelect json字符串* @param columnType 数据库字段类型* @return*/public static String getRangeParseUtil(String rangeSelect, String columnType) {if (StringUtils.isEmpty(rangeSelect) || StringUtils.isEmpty(columnType)) {return null;}//通过类型取字段最大值最小值DBFieldType dbFieldType = DBFieldType.getDBFieldType(columnType);ObjectMapper objectMapper = new ObjectMapper();List<Range> list;try {list = objectMapper.readValue(rangeSelect, new TypeReference<List<Range>>() {});} catch (JsonProcessingException e) {throw new RuntimeException(e);}if (CollectionUtils.isEmpty(list)) {return null;}//将json转换为开闭区间List<String> builderList = new ArrayList<>();list.forEach(range -> {//返回的可能是分号;隔开的两个区间String parse = range.parse(dbFieldType);if (StringUtils.isNotEmpty(parse)) {String[] split = parse.split(Constant.SEMICOLON);builderList.addAll(Arrays.asList(split));}});if (CollectionUtils.isEmpty(builderList)) {return null;}//取最大值 最小值 不在这个区间范围的 放在另一个区间 或者是另外两个区间//类型不同 比较大小的方式不同//每一组元素 [1,2] (3,4) [5,6) (7,8] 第一个符号和第一个逗号之间是最小数字 第一个逗号到倒数第二个是最大数字//最后要对区间中断的情况处理switch (dbFieldType) {case INT:compareInt(builderList);break;case LONG:compareLong(builderList);break;case FLOAT:compareFloat(builderList);break;case DOUBLE:compareDouble(builderList);break;}//转换成;拼接的数组返回return String.join(Constant.SEMICOLON, builderList);}/*** float类型处理* 循环比较 找出最小的 和最大的 并且取出来最小最大分别是开区间还是闭区间 用于组合默认区间 默认区间可能有两个 头一个 尾一个* * [最小值,1)* * [1,100)* * [101,300)* * [300,最大值)** @param builderList*/private static void compareFloat(List<String> builderList) {String leftSymbol = null;String rightSymbol = null;Float minThis = null;Float maxThis = null;//最后用于比较排序 从而补充间断区间的listList<Range<Float>> compareList = new ArrayList<>();for (String expression : builderList) {//当前符号String currentLeftSymbol = expression.substring(0, 1);String currentRightSymbol = expression.substring(expression.length() - 1, expression.length());//第一个符号和第一个逗号之间是最小数字Float minMid = Float.valueOf(expression.substring(1, expression.indexOf(Constant.COMMA_SPLIT)));//空就赋值if (minThis == null) {minThis = minMid;leftSymbol = currentLeftSymbol;}//跟最小值比谁大if (minMid.compareTo(minThis) < 0) {minThis = minMid;leftSymbol = currentLeftSymbol;}//第一个逗号到倒数第二个是最大数字Float maxMid = Float.valueOf(expression.substring(expression.indexOf(Constant.COMMA_SPLIT) + 1, expression.length() - 1));//空就赋值if (maxThis == null) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//跟最大值比谁大if (maxMid.compareTo(maxThis) > 0) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//取当前的开闭区间符号去构建RangeCompareRange<Float> compare = Range.<Float>builder().leftSymbol(currentLeftSymbol).leftNum(minMid).relation(Constant.COMMA_SPLIT).rightNum(maxMid).rightSymbol(currentRightSymbol).build();compareList.add(compare);}//把所有区间最小值 和 这个字段类型的最小值比较 如果min<minThis 就还有一个更小的区间 区间范围是min,minThis 至于开闭 要看leftSymbol leftSymbol为闭 则(min,minThis) leftSymbol为开 则(min,minThis]if (minThis.compareTo(Float.MIN_VALUE) > 0) {StringBuilder builder = new StringBuilder();builder.append(Range.LEFT_OPEN).append(Float.MIN_VALUE).append(Constant.COMMA_SPLIT).append(minThis);if (Range.LEFT_OPEN.equals(leftSymbol)) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(leftSymbol)) {builder.append(Range.RIGHT_OPEN);}builderList.add(builder.toString());}//把所有区间最大值 和这个字段类型的最大值比较 如果max>maxThis 就还有一个更大的区间 区间范围是maxThis,max 至于开闭 要看rightSymbol rightSymbol为闭 则(maxThis,max) rightSymbol为开 则[maxThis,max)if (maxThis.compareTo(Float.MAX_VALUE) < 0) {StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(rightSymbol)) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(rightSymbol)) {builder.append(Range.LEFT_OPEN);}builder.append(maxThis).append(Constant.COMMA_SPLIT).append(Float.MAX_VALUE).append(Range.RIGHT_OPEN);builderList.add(builder.toString());}//补充中断区间addFloat(compareList, builderList);}/**** builderList 补充好了最大值区间和最小值区间* compareList 没补充最大值区间 最小值区间* compareList 查缺 查现有数据的中断区间* addList 补漏 把compareList排序后发现中断的区间 放到addList中* 最后builderList+addList 就是全集** @param compareList* @param builderList*/private static void addDouble(List<Range<Double>> compareList, List<String> builderList) {//最大值最小值补充完后 整个list排序 看区间是否连续 不连续就补充区间//先按照左边得数排序 左边数相等得时候 再按照右边的数排序compareList.sort(Comparator.comparing(Range<Double>::getLeftNum).thenComparing(Range<Double>::getRightNum));List<String> addList = new ArrayList<>();//有序list 每个元素的右区间beforeRight和下一个元素的左区间nextLeft比较,如果有区间beforeRight<nextLeft 就是不连续区间//设置中间值 作为上个元素 用于循环中比较Range<Double> before = null;for (Range<Double> compare : compareList) {if (Objects.nonNull(before)) {int i = before.getRightNum().compareTo(compare.getLeftNum());//如果有区间beforeRight<nextLeft 就是不连续区间if (i < 0) {//新增的区间beforeRight,nextLeft 至于开闭 需要看beforeRightSymbol 和 nextLeftSymbol 取反StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(before.getRightSymbol())) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(before.getRightSymbol())) {builder.append(Range.LEFT_OPEN);}builder.append(before.getRightNum()).append(Constant.COMMA_SPLIT).append(compare.getLeftNum());if (Range.LEFT_OPEN.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_OPEN);}addList.add(builder.toString());}}//给下一个元素比较时候用before = compare;}if (CollectionUtils.isNotEmpty(addList)) {builderList.addAll(addList);}}/**** builderList 补充好了最大值区间和最小值区间* compareList 没补充最大值区间 最小值区间* compareList 查缺 查现有数据的中断区间* addList 补漏 把compareList排序后发现中断的区间 放到addList中* 最后builderList+addList 就是全集** @param compareList* @param builderList*/private static void addLong(List<Range<Long>> compareList, List<String> builderList) {//最大值最小值补充完后 整个list排序 看区间是否连续 不连续就补充区间//先按照左边得数排序 左边数相等得时候 再按照右边的数排序compareList.sort(Comparator.comparing(Range<Long>::getLeftNum).thenComparing(Range<Long>::getRightNum));List<String> addList = new ArrayList<>();//有序list 每个元素的右区间beforeRight和下一个元素的左区间nextLeft比较,如果有区间beforeRight<nextLeft 就是不连续区间//设置中间值 作为上个元素 用于循环中比较Range<Long> before = null;for (Range<Long> compare : compareList) {if (Objects.nonNull(before)) {int i = before.getRightNum().compareTo(compare.getLeftNum());//如果有区间beforeRight<nextLeft 就是不连续区间if (i < 0) {//新增的区间beforeRight,nextLeft 至于开闭 需要看beforeRightSymbol 和 nextLeftSymbol 取反StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(before.getRightSymbol())) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(before.getRightSymbol())) {builder.append(Range.LEFT_OPEN);}builder.append(before.getRightNum()).append(Constant.COMMA_SPLIT).append(compare.getLeftNum());if (Range.LEFT_OPEN.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_OPEN);}addList.add(builder.toString());}}//给下一个元素比较时候用before = compare;}if (CollectionUtils.isNotEmpty(addList)) {builderList.addAll(addList);}}/*** * builderList 补充好了最大值区间和最小值区间* compareList 没补充最大值区间 最小值区间* compareList 查缺 查现有数据的中断区间* addList 补漏 把compareList排序后发现中断的区间 放到addList中* 最后builderList+addList 就是全集* * @param compareList* @param builderList*/private static void addInt(List<Range<Integer>> compareList, List<String> builderList) {//最大值最小值补充完后 整个list排序 看区间是否连续 不连续就补充区间//先按照左边得数排序 左边数相等得时候 再按照右边的数排序compareList.sort(Comparator.comparing(Range<Integer>::getLeftNum).thenComparing(Range<Integer>::getRightNum));List<String> addList = new ArrayList<>();//有序list 每个元素的右区间beforeRight和下一个元素的左区间nextLeft比较,如果有区间beforeRight<nextLeft 就是不连续区间//设置中间值 作为上个元素 用于循环中比较Range<Integer> before = null;for (Range<Integer> compare : compareList) {if (Objects.nonNull(before)) {int i = before.getRightNum().compareTo(compare.getLeftNum());//如果有区间beforeRight<nextLeft 就是不连续区间if (i < 0) {//新增的区间beforeRight,nextLeft 至于开闭 需要看beforeRightSymbol 和 nextLeftSymbol 取反StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(before.getRightSymbol())) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(before.getRightSymbol())) {builder.append(Range.LEFT_OPEN);}builder.append(before.getRightNum()).append(Constant.COMMA_SPLIT).append(compare.getLeftNum());if (Range.LEFT_OPEN.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_OPEN);}addList.add(builder.toString());}}//给下一个元素比较时候用before = compare;}if (CollectionUtils.isNotEmpty(addList)) {builderList.addAll(addList);}}/**** builderList 补充好了最大值区间和最小值区间* compareList 没补充最大值区间 最小值区间* compareList 查缺 查现有数据的中断区间* addList 补漏 把compareList排序后发现中断的区间 放到addList中* 最后builderList+addList 就是全集** @param compareList* @param builderList*/private static void addFloat(List<Range<Float>> compareList, List<String> builderList) {//最大值最小值补充完后 整个list排序 看区间是否连续 不连续就补充区间//先按照左边得数排序 左边数相等得时候 再按照右边的数排序compareList.sort(Comparator.comparing(Range<Float>::getLeftNum).thenComparing(Range<Float>::getRightNum));List<String> addList = new ArrayList<>();//有序list 每个元素的右区间beforeRight和下一个元素的左区间nextLeft比较,如果有区间beforeRight<nextLeft 就是不连续区间//设置中间值 作为上个元素 用于循环中比较Range<Float> before = null;for (Range<Float> compare : compareList) {if (Objects.nonNull(before)) {int i = before.getRightNum().compareTo(compare.getLeftNum());//如果有区间beforeRight<nextLeft 就是不连续区间if (i < 0) {//新增的区间beforeRight,nextLeft 至于开闭 需要看beforeRightSymbol 和 nextLeftSymbol 取反StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(before.getRightSymbol())) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(before.getRightSymbol())) {builder.append(Range.LEFT_OPEN);}builder.append(before.getRightNum()).append(Constant.COMMA_SPLIT).append(compare.getLeftNum());if (Range.LEFT_OPEN.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(compare.getLeftSymbol())) {builder.append(Range.RIGHT_OPEN);}addList.add(builder.toString());}}//给下一个元素比较时候用before = compare;}if (CollectionUtils.isNotEmpty(addList)) {builderList.addAll(addList);}}/*** double类型处理* 循环比较 找出最小的 和最大的 并且取出来最小最大分别是开区间还是闭区间 用于组合默认区间 默认区间可能有两个 头一个 尾一个* * [最小值,1)* * [1,100)* * [101,300)* * [300,最大值)** @param builderList*/private static void compareDouble(List<String> builderList) {String leftSymbol = null;String rightSymbol = null;Double minThis = null;Double maxThis = null;//最后用于比较排序 从而补充间断区间的listList<Range<Double>> compareList = new ArrayList<>();for (String expression : builderList) {//当前符号String currentLeftSymbol = expression.substring(0, 1);String currentRightSymbol = expression.substring(expression.length() - 1, expression.length());//第一个符号和第一个逗号之间是最小数字Double minMid = Double.valueOf(expression.substring(1, expression.indexOf(Constant.COMMA_SPLIT)));//空就赋值if (minThis == null) {minThis = minMid;leftSymbol = currentLeftSymbol;}//跟最小值比谁大if (minMid.compareTo(minThis) < 0) {minThis = minMid;leftSymbol = currentLeftSymbol;}//第一个逗号到倒数第二个是最大数字Double maxMid = Double.valueOf(expression.substring(expression.indexOf(Constant.COMMA_SPLIT) + 1, expression.length() - 1));//空就赋值if (maxThis == null) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//跟最大值比谁大if (maxMid.compareTo(maxThis) > 0) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//取当前的开闭区间符号去构建RangeCompareRange<Double> compare = Range.<Double>builder().leftSymbol(currentLeftSymbol).leftNum(minMid).relation(Constant.COMMA_SPLIT).rightNum(maxMid).rightSymbol(currentRightSymbol).build();compareList.add(compare);}//把所有区间最小值 和 这个字段类型的最小值比较 如果min<minThis 就还有一个更小的区间 区间范围是min,minThis 至于开闭 要看leftSymbol leftSymbol为闭 则(min,minThis) leftSymbol为开 则(min,minThis]if (minThis.compareTo(Double.MIN_VALUE) > 0) {StringBuilder builder = new StringBuilder();builder.append(Range.LEFT_OPEN).append(Double.MIN_VALUE).append(Constant.COMMA_SPLIT).append(minThis);if (Range.LEFT_OPEN.equals(leftSymbol)) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(leftSymbol)) {builder.append(Range.RIGHT_OPEN);}builderList.add(builder.toString());}//把所有区间最大值 和这个字段类型的最大值比较 如果max>maxThis 就还有一个更大的区间 区间范围是maxThis,max 至于开闭 要看rightSymbol rightSymbol为闭 则(maxThis,max) rightSymbol为开 则[maxThis,max)if (maxThis.compareTo(Double.MAX_VALUE) < 0) {StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(rightSymbol)) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(rightSymbol)) {builder.append(Range.LEFT_OPEN);}builder.append(maxThis).append(Constant.COMMA_SPLIT).append(Double.MAX_VALUE).append(Range.RIGHT_OPEN);builderList.add(builder.toString());}//补充中断区间addDouble(compareList, builderList);}/*** int类型处理* 循环比较 找出最小的 和最大的 并且取出来最小最大分别是开区间还是闭区间 用于组合默认区间 默认区间可能有两个 头一个 尾一个* * [最小值,1)* * [1,100)* * [101,300)* * [300,最大值)** @param builderList*/private static void compareInt(List<String> builderList) {String leftSymbol = null;String rightSymbol = null;Integer minThis = null;Integer maxThis = null;//最后用于比较排序 从而补充间断区间的listList<Range<Integer>> compareList = new ArrayList<>();for (String expression : builderList) {//当前开闭区间符号String currentLeftSymbol = expression.substring(0, 1);String currentRightSymbol = expression.substring(expression.length() - 1, expression.length());//第一个符号和第一个逗号之间是最小数字Integer minMid = Integer.valueOf(expression.substring(1, expression.indexOf(Constant.COMMA_SPLIT)));//空就先赋值if (minThis == null) {minThis = minMid;leftSymbol = currentLeftSymbol;}//跟最小值比谁大if (minMid.compareTo(minThis) < 0) {minThis = minMid;leftSymbol = currentLeftSymbol;}//第一个逗号到倒数第二个是最大数字Integer maxMid = Integer.valueOf(expression.substring(expression.indexOf(Constant.COMMA_SPLIT) + 1, expression.length() - 1));//空就先赋值if (maxThis == null) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//跟最大值比谁大if (maxMid.compareTo(maxThis) > 0) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//取当前的开闭区间符号去构建RangeCompareRange<Integer> compare = Range.<Integer>builder().leftSymbol(currentLeftSymbol).leftNum(minMid).relation(Constant.COMMA_SPLIT).rightNum(maxMid).rightSymbol(currentRightSymbol).build();compareList.add(compare);}//把所有区间最小值 和 这个字段类型的最小值比较 如果min<minThis 就还有一个更小的区间 区间范围是min,minThis 至于开闭 要看leftSymbol leftSymbol为闭 则(min,minThis) leftSymbol为开 则(min,minThis]if (minThis.compareTo(Integer.MIN_VALUE) > 0) {StringBuilder builder = new StringBuilder();builder.append(Range.LEFT_OPEN).append(Integer.MIN_VALUE).append(Constant.COMMA_SPLIT).append(minThis);if (Range.LEFT_OPEN.equals(leftSymbol)) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(leftSymbol)) {builder.append(Range.RIGHT_OPEN);}builderList.add(builder.toString());}//把所有区间最大值 和这个字段类型的最大值比较 如果max>maxThis 就还有一个更大的区间 区间范围是maxThis,max 至于开闭 要看rightSymbol rightSymbol为闭 则(maxThis,max) rightSymbol为开 则[maxThis,max)if (maxThis.compareTo(Integer.MAX_VALUE) < 0) {StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(rightSymbol)) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(rightSymbol)) {builder.append(Range.LEFT_OPEN);}builder.append(maxThis).append(Constant.COMMA_SPLIT).append(Integer.MAX_VALUE).append(Range.RIGHT_OPEN);builderList.add(builder.toString());}//补充中断区间addInt(compareList, builderList);}/*** Long类型处理* 循环比较 找出最小的 和最大的 并且取出来最小最大分别是开区间还是闭区间 用于组合默认区间 默认区间可能有两个 头一个 尾一个* * [最小值,1)* * [1,100)* * [101,300)* * [300,最大值)** @param builderList*/private static void compareLong(List<String> builderList) {String leftSymbol = null;String rightSymbol = null;Long minThis = null;Long maxThis = null;//最后用于比较排序 从而补充间断区间的listList<Range<Long>> compareList = new ArrayList<>();for (String expression : builderList) {//当前开闭区间符号String currentLeftSymbol = expression.substring(0, 1);String currentRightSymbol = expression.substring(expression.length() - 1, expression.length());//第一个符号和第一个逗号之间是最小数字Long minMid = Long.valueOf(expression.substring(1, expression.indexOf(Constant.COMMA_SPLIT)));//空就先赋值if (minThis == null) {minThis = minMid;leftSymbol = currentLeftSymbol;}//跟最小值比谁大if (minMid.compareTo(minThis) < 0) {minThis = minMid;leftSymbol = currentLeftSymbol;}//第一个逗号到倒数第二个是最大数字Long maxMid = Long.valueOf(expression.substring(expression.indexOf(Constant.COMMA_SPLIT) + 1, expression.length() - 1));//空就先赋值if (maxThis == null) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//跟最大值比谁大if (maxMid.compareTo(maxThis) > 0) {maxThis = maxMid;rightSymbol = currentRightSymbol;}//取当前的开闭区间符号去构建RangeCompareRange<Long> compare = Range.<Long>builder().leftSymbol(currentLeftSymbol).leftNum(minMid).relation(Constant.COMMA_SPLIT).rightNum(maxMid).rightSymbol(currentRightSymbol).build();compareList.add(compare);}//把所有区间最小值 和 这个字段类型的最小值比较 如果min<minThis 就还有一个更小的区间 区间范围是min,minThis 至于开闭 要看leftSymbol leftSymbol为闭 则(min,minThis) leftSymbol为开 则(min,minThis]if (minThis.compareTo(Long.MIN_VALUE) > 0) {StringBuilder builder = new StringBuilder();builder.append(Range.LEFT_OPEN).append(Long.MIN_VALUE).append(Constant.COMMA_SPLIT).append(minThis);if (Range.LEFT_OPEN.equals(leftSymbol)) {builder.append(Range.RIGHT_CLOSE);} else if (Range.LEFT_CLOSE.equals(leftSymbol)) {builder.append(Range.RIGHT_OPEN);}builderList.add(builder.toString());}//把所有区间最大值 和这个字段类型的最大值比较 如果max>maxThis 就还有一个更大的区间 区间范围是maxThis,max 至于开闭 要看rightSymbol rightSymbol为闭 则(maxThis,max) rightSymbol为开 则[maxThis,max)if (maxThis.compareTo(Long.MAX_VALUE) < 0) {StringBuilder builder = new StringBuilder();if (Range.RIGHT_OPEN.equals(rightSymbol)) {builder.append(Range.LEFT_CLOSE);} else if (Range.RIGHT_CLOSE.equals(rightSymbol)) {builder.append(Range.LEFT_OPEN);}builder.append(maxThis).append(Constant.COMMA_SPLIT).append(Long.MAX_VALUE).append(Range.RIGHT_OPEN);builderList.add(builder.toString());}//补充中断区间addLong(compareList, builderList);}public static void main(String[] args) {//String select = "[{\"leftSymbol\":\">=\",\"leftNum\":50,\"relation\":\"且\",\"rightSymbol\":\"<\",\"rightNum\":100},{\"leftSymbol\":\">=\",\"leftNum\":10,\"relation\":\"且\",\"rightSymbol\":\"<\",\"rightNum\":50},{\"leftSymbol\":\"<\",\"leftNum\":10,\"relation\":\"无\",\"rightSymbol\":null,\"rightNum\":null}]\n";//String select = "[{\"leftSymbol\":\">=\",\"leftNum\":1,\"relation\":\"且\",\"rightSymbol\":\"<\",\"rightNum\":100},{\"leftSymbol\":\">=\",\"leftNum\":100,\"relation\":\"且\",\"rightSymbol\":\"<\",\"rightNum\":300}]";String select = "[{\"leftSymbol\":\">=\",\"leftNum\":10,\"relation\":\"无\",\"rightSymbol\":null,\"rightNum\":null}]";String bigint = getRangeParseUtil(select, "FLOAT");System.out.println(bigint);}}
相关文章:
json字符串转为开闭区间
1.需求背景 1.1 前端页面展示 1.2 前后端约定交互json 按照页面每一行的从左到右 * 示例 [{"leftSymbol":">","leftNum":100,"relation":"无","rightSymbol":null,"rightNum":0}, {"left…...
STM32 IIC 实验
1. 可以选择I2C1,也可以选择I2C2,或者同时选择,同时运行 配置时钟信号 为节约空间,选择这两个,然后选择GENERATE CODE 二、HAL_I2C_Mem_Write I2C_HandleTypeDef *hi2c:I2C设备句柄 uint16_t DevAddress&am…...
第六章 包图组织模型|系统建模语言SysML实用指南学习
仅供个人学习记录 概述 包是容器的一个例子。包中的模型元素称为可封装元素,这些元素可以是包、用例和活动。由于包本身也是可封装元素,因此可以支持包层级。 每个有名称的模型元素也必须是命名空间的一份子,命名空间使得每个元素均能够通过…...
使用 Rust 进行程序
首先,我们需要安装必要的库。在终端中运行以下命令来安装 scraper 和 reqwest 库: rust cargo install scraper reqwest 然后,我们可以开始编写程序。以下是一个基本的爬虫程序,用于爬取 上的图片: rust use reqwe…...
第10章 增长和扩展你的 Micro SaaS 应用程序
接下来,我们进入真正增长 Micro SaaS 应用用户群和订阅收入的激动人心的话题。 即使在增长阶段,你也不能忽视客户满意度,确保你与时俱进,在路线图上添加你承诺的功能,然后通过 SaaS 营销吸引更多用户。 也就是说,让我们来看看增长您的 Micro SaaS 应用程序的关键战略要…...
第八章《搞懂算法:逻辑回归是怎么回事》笔记
8.1 如何理解逻辑回归 逻辑回归根据给定的自变量数据集来估计事件的发生概率,由于结果是一个概率,因此因变量的范围在 0 和 1 之间。 逻辑回归的与线性回归一样,也是以线性函数为基础的;而与线性回归不同的是,逻辑回…...
【WinForm详细教程八】WinForm中的TreeView控件
文章目录 TreeView 基本的知识属性方法事件 TreeView 案例演示案例一:案例二: TreeView 控件 用于展示分层数据,它以树形结构展示信息,每个节点可以有一个或多个子节点。TreeView 控件允许用户以可展开和可折叠的形式查看复杂的层…...
〔003〕虚幻 UE5 基础教程和蓝图入门
✨ 目录 🎈 新建项目🎈 快捷操作🎈 镜头移动速度🎈 新建蓝图关卡🎈 打印字符串🎈 蓝图的快捷键🎈 场景中放置物体🎈 通过蓝图改变物体位置🎈 展现物体运动轨迹dz…...
如何像优秀测试人员那样思考?
优秀测试和普通测试之间的差别在于测试人员如何思考:测试人员的测试设计选择,解释所观察到的能力,以及非常令人信服地分析描述这些现象的能力。 然而,在实际工作中,我们更多的看到了测试人员在电脑前点点点࿰…...
NOIP2023模拟13联测34 A. origenNOIP2023模拟13联测34 A. origen
NOIP2023模拟13联测34 A. origen 文章目录 NOIP2023模拟13联测34 A. origen题目大意思路code 题目大意 给定 n n n 个整数 a 1 , a 2 , a 3 ⋯ a n a_1,a_2,a_3\cdots a_n a1,a2,a3⋯an ,求 ∑ i 1 n ∑ j i n ( ⊕ k i j a k ) 2 m o d 998244353 \…...
HttpClient学习(Java)
一、介绍 HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的版本和建议。 我们可以通过这个HttpClient工具,在java代码中去构造和发送ht…...
信息系统项目管理师之各工具的定义及解释
数据收集技术 用于从各种渠道收集数据与信息。 数据分析技术 用于组织评估和评价数据与信息。 数据表现技术 用于显示用来传递数据和信息的图形方式或其他方法。 决策技术 用于从不同备选方案选择行动方案。 沟通技巧 用于在干系人之间传递信息。 人际关系与团队技能…...
golang的defer执行时机案例分析
package main import "fmt"func calcFunc(x int, y int) int {return x y }func main() {// defer语句的执行顺序是,从右到左,逆序执行deferDemo()// deferDemo1函数demo1 : deferDemo1()fmt.Println(demo1) // 0// deferDemo2函数demo2 : deferDemo2()f…...
2.HTML中常用浏览器
2.常用浏览器 2.1 什么是浏览器 浏览器是网页显示,运行的平台。常用的浏览器有IE,火狐,谷歌,Safari和Opera等 平时成为五大浏览器 2.2 浏览器内核 浏览器内核(渲染引擎):负责读取网页内容&…...
Vue 监听store数据变化
天冷了,手也冷了,于学问于个人成长不能因为冷而荒废。毕业这么多年,只能感慨。这样努力的工作只是解决了温保问题,何时才能任性的过一回说走就走的自由生活? 大抵这样的梦想也就只能停留在梦里与期待中吧,与…...
智能交通和自动驾驶技术
一、定义 智能交通和自动驾驶技术是指利用先进的信息技术和人工智能技术,实现交通系统的智能化和自动化。智能交通和自动驾驶技术不仅可以提高交通系统的效率和安全性,还可以改善人们的出行体验,促进城市可持续发展。 智能交通和自动驾驶技…...
CentOS7安装部署StarRocks
文章目录 CentOS7安装部署StarRocks一、前言1.简介2.环境 二、正文1.StarRocks基础1)架构图2)通讯端口 2.部署服务器3.安装基础环境1)安装JDK 112)修改机器名3)安装GCC4)关闭交换分区(swap&…...
树形Dp 2925. 在树上执行操作以后得到的最大分数
2925. 在树上执行操作以后得到的最大分数 两次DFS class Solution { public:// 节点状态有两种,选和不选,// dp(u, fa, 0) 不选u 节点,其他节点都可以选,值为以u为根的子树的所有节点的和- 根节点的值。// dp(u, fa, 1) 选u节点&…...
选择企业云盘?品牌推荐和评价解析
企业云盘是如今热门的企业协作工具,为企业提供了文件存储、文件共享服务。市面上的企业云盘千千万,到底哪个企业云盘好用?哪些品牌值得信赖呢? 好用的企业云盘,不能不提,Zoho Workdrive企业云盘为企业提供…...
redis: 记录一次线上redis内存占用过大问题解决过程
引言 记录一次线上redis占用过大的排查过程,供后续参考 问题背景 测试同事突然反馈测试环境的web系统无法登陆,同时发现其他子系统也存在各类使用问题 排查过程 1、因为首先反馈的是测试环境系统无法登陆,于是首先去查看了登陆功能的报错…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
HDFS分布式存储 zookeeper
hadoop介绍 狭义上hadoop是指apache的一款开源软件 用java语言实现开源框架,允许使用简单的变成模型跨计算机对大型集群进行分布式处理(1.海量的数据存储 2.海量数据的计算)Hadoop核心组件 hdfs(分布式文件存储系统)&a…...
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...
JS手写代码篇----使用Promise封装AJAX请求
15、使用Promise封装AJAX请求 promise就有reject和resolve了,就不必写成功和失败的回调函数了 const BASEURL ./手写ajax/test.jsonfunction promiseAjax() {return new Promise((resolve, reject) > {const xhr new XMLHttpRequest();xhr.open("get&quo…...
