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、因为首先反馈的是测试环境系统无法登陆,于是首先去查看了登陆功能的报错…...

JavaSec-RCE
简介 RCE(Remote Code Execution),可以分为:命令注入(Command Injection)、代码注入(Code Injection) 代码注入 1.漏洞场景:Groovy代码注入 Groovy是一种基于JVM的动态语言,语法简洁,支持闭包、动态类型和Java互操作性,…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
Go语言多线程问题
打印零与奇偶数(leetcode 1116) 方法1:使用互斥锁和条件变量 package mainimport ("fmt""sync" )type ZeroEvenOdd struct {n intzeroMutex sync.MutexevenMutex sync.MutexoddMutex sync.Mutexcurrent int…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...