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、因为首先反馈的是测试环境系统无法登陆,于是首先去查看了登陆功能的报错…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...

css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)
目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关࿰…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...