住房城乡建设干部学院网站/整站优化快速排名
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、因为首先反馈的是测试环境系统无法登陆,于是首先去查看了登陆功能的报错…...

数据资产、数字资产、数据资源及数据资产入表
数据要素 《中共中央关于坚持和完善中国特色社会主义制度推进国家治理体系和治理能力现代化若干重大的决议》(2019) 首次将数据列为生产要素 《关于构建更加完善的要素市场化配置体制机制的意见》(2020.3) 数据成为土地、劳动力、…...

Docker之Centos安装
介绍 Docker官方建议在Ubuntu中安装,因为Docker是基于Ubuntu发布的, 而且一般Docker出现的问题Ubuntu是最先更新或者打补丁的。 在很多版本的CentOS中是不支持更新最新的一些补丁包的。由于我们学习的环境都使用的是CentOS,因此这里我们将Do…...

SQL注入漏洞:CMS布尔盲注python脚本编写
SQL注入漏洞:CMS布尔盲注python脚本编写 文章目录 SQL注入漏洞:CMS布尔盲注python脚本编写库名爆破爆破表名用户名密码爆破 库名爆破 import requests #库名 database"" x0 while requests.get(urlf"http://10.9.47.77/cms/show.php?id33%20and%20length(data…...

security
Java Security 是一个用于在 Java 平台上提供安全性的框架。下面是 Java Security 的一些主要知识点: 1. 加密和解密:Java Security 提供了一组加密和解密 API,可以实现各种加密标准,如 AES、DES、RSA 等。 2. 数字签名…...

了解web3,什么是web3
Web3是指下一代互联网,它基于区块链技术,将各种在线活动更加安全、透明和去中心化。Web3是一个广义的概念,它包括了很多方面,如数字货币、去中心化应用、智能合约等等。听不懂且大多数人听到这个东西,直觉感觉就像骗子…...

Harbor企业级Registry基础镜像仓库的详细安装使用教程(保姆级)
Harbor Docker 官方提供的私有仓库 registry,用起来虽然简单 ,但在管理的功能上存在不足。 Harbor是vmware一个用于存储和分发Docker镜像的企业级Registry服务器,harbor使用的是官方的docker registry(v2命名是distribution)服务去完成。 ha…...

Linux系统下数据同步服务RSYNC
一、RSYNC概述 1、什么是rsync rsync的好姐妹 sync 同步:刷新文件系统缓存,强制将修改过的数据块写入磁盘,并且更新超级块。 async 异步:将数据先放到缓冲区,再周期性(一般是30s)的去同步到磁…...

Docker介绍及其常用命令
Docker是一种容器化技术,可以打包应用程序及其依赖项,并将其作为独立的进程运行。它实现了操作系统级别的虚拟化,允许不同容器之间相互隔离,同时提高了应用程序的可移植性和安全性。Docker可以快速部署和扩展应用程序,…...

SwissArmyTransformer瑞士军刀工具箱使用手册
Introduction sat(SwissArmyTransformer)是一个灵活而强大的库,用于开发您自己的Transformer变体。 sat是以“瑞士军刀”命名的,这意味着所有型号(例如BERT、GPT、T5、GLM、CogView、ViT…)共享相同的backo…...

unity【动画】脚本_角色动画控制器 c#
首先创建一个代码文件夹Scripts 从人物角色Player的基类开始 创建IPlayer类 首先我们考虑到如果不挂载MonoBehaviour需要将角色设置成预制体实例化到场景上十分麻烦, 所以我们采用继承MonoBehaviour类的角色基类方法写代码 也就是说这个脚本直接绑定在角色物体…...