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转List
        List<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;
        //最后用于比较排序  从而补充间断区间的list
        List<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;
            }
            //取当前的开闭区间符号去构建RangeCompare
            Range<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;
        //最后用于比较排序  从而补充间断区间的list
        List<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;
            }
            //取当前的开闭区间符号去构建RangeCompare
            Range<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;
        //最后用于比较排序  从而补充间断区间的list
        List<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;
            }
            //取当前的开闭区间符号去构建RangeCompare
            Range<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;
        //最后用于比较排序  从而补充间断区间的list
        List<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;
            }
            //取当前的开闭区间符号去构建RangeCompare
            Range<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);
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/127470.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用于强化学习的置换不变神经网络

一、介绍 如果强化学习代理提供的输入在训练中未明确定义&#xff0c;则通常表现不佳。一种新方法使 RL 代理能够正常运行&#xff0c;即使受到损坏、不完整或混乱的输入的影响也是如此。 “大脑能够使用来自皮肤的信息&#xff0c;就好像它来自眼睛一样。我们不是用眼睛看&…

笔记本电脑的麦克风没有声音

笔记本电脑的麦克风没有声音是一个常见的问题&#xff0c;可能是由于以下几个原因导致的&#xff1a; 第一&#xff0c;麦克风没有启用或者被禁用了。在Windows系统中&#xff0c;右键单击任务栏上的音量图标&#xff0c;选择“录音设备”&#xff0c;在弹出窗口中找到麦克风&a…

Webpack--动态 import 原理及源码分析

前言 在平时的开发中&#xff0c;我们经常使用 import()实现代码分割和懒加载。在低版本的浏览器中并不支持动态 import()&#xff0c;那 webpack 是如何实现 import() polyfill 的&#xff1f; 原理分析 我们先来看看下面的 demo function component() {const btn docume…

JavaScript_Node节点属性_nodeName

nodeName属性&#xff1a;返回节点的名称 节点的类型有七种 Document&#xff1a;整个文档树的顶层节点 DocumentType&#xff1a;doctype标签 Element&#xff1a;网页的各种HTML标签 Attribute&#xff1a;网页元素的属性 Text&#xff1a;标签之间或标签包含的文本 C…

box-shadow用法详解

1、box-shadow概述 用来实现对元素产生阴影效果 1.1、box-shadow常用属性 box-shadow: h-shading v-shading blur spread color inset; box-shadow: X轴偏移量 Y轴偏移量 阴影模糊半径 阴影扩展半径 阴影颜色 投影方式…

完蛋!我被LLM包围了!上个时代的开发者被干掉了;ChatGPT高质量科普视频;垂直领域大模型的思考;百度智能云黑客松 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f440; 百度智能云 | 千帆大模型平台黑客马拉松 https://segmentfault.com/e/1160000044353489 百度智能云携手 SegmentFault 思否&#xff0…

如何理解CDN?说说实现原理?

面试官&#xff1a;如何理解CDN&#xff1f;说说实现原理&#xff1f; 一、是什么 CDN (全称 Content Delivery Network)&#xff0c;即内容分发网络 构建在现有网络基础之上的智能虚拟网络&#xff0c;依靠部署在各地的边缘服务器&#xff0c;通过中心平台的负载均衡、内容分…

数据结构与算法—冒泡排序快速排序

目录 一、交换排序 二、冒泡排序 时间复杂度 三、快速排序 1、三种一次划分操作 Hoare法 挖洞法 前后指针法 三种方法总结&#xff1a; 2、改进划分效率 3、递归实现快速排序 4、非递归实现快速排序 栈的函数&#xff1a; 非递归排序函数&#xff1a; 5、时…

MySQL常用时间函数

1.NOW()&#xff1a;返回当前日期和时间。 SELECT NOW()2.CURDATE()&#xff1a;返回当前日期。 SELECT CURDATE();3.CURTIME()&#xff1a;返回当前时间。 SELECT CURTIME();4.DATE()&#xff1a;提取日期或日期时间表达式的日期部分。 SELECT DATE(NOW());5.TIME()&#…

8 mysql中的索引2

一、索引的种类 1、 B树索引 1.**每个索引就是一颗B树**&#xff0c;二级索引不包含行记录的全部数据 2.叶子节点除了包含键值以外&#xff0c;每个叶子节点中的索引行中还包含了一个书签( bookmark) 3.B平衡树是一颗查找树&#xff0c;B树的叶子节点用来放数据的,并且所有叶…

开发知识点-golang

golang语言学习 环境搭建win10配置go环境 ubuntu20.04安装golang介绍下载 Go 压缩包调整环境变量验证 Go 安装过程 环境搭建 win10配置go环境 中文网进行下载 https://studygolang.com/dl 配置环境变量 增加GOROOT: 新建 -->变量名为: GOROOT(必须大写) 变量值: 你安装…

CSS3 用户界面、图片、按钮

一、CSS3用户界面&#xff1a; 在CSS3中&#xff0c;增加了一些新的用户界面特性来调整元素尺寸、框尺寸和外边框。CSS3用户界面属性&#xff1a;resize、box-sizing、outline-offset。 1、resize&#xff1a; resize属性指定一个元素是否应该由用户去调整大小。 <style…

C++类和对象(上)

目录 C入门知识补充auto关键字&#xff08;C11&#xff09;基于范围的for循环&#xff08;C11&#xff09;nullptr&#xff08;C11&#xff09; 类和对象面向过程 OR 面向对象初步认识类的引入类的定义类的访问限定符类的作用域类的实例化类对象模型计算类对象的大小 在这里插入…

虚幻C++基础 day4

虚幻中的UI 虚幻中的比较常用的UI&#xff1a;Widget Blueprint又称UMG虚幻中的两种布局&#xff1a; 网格布局锚布局 创建Widget Blueprint 网格布局 有点类似Qt中的网格布局&#xff0c;将UI面板进行行列切分Horizontal Box&#xff1a;水平分布Vertical Box&#xff1a;…

短剧出海火爆,Flat Ads独家流量助泛娱乐赛道App迅速获客增长

10月26日&#xff0c;由扬帆出海主办的GICC2023 | 第四届全球互联网产业CEO大会正式圆满落幕&#xff0c;Flat Ads等出海企业应邀参加。 据悉&#xff0c;本届GICC深圳站邀请200CXO行业领袖、300各路优质厂商、1200全球互联网产业代表共聚一堂&#xff0c;聚焦短剧、游戏、泛娱…

vim相关命令讲解!

本文旨在讲解vim 以及其相关的操作&#xff01; 希望读完本文&#xff0c;读者会有一定的收获&#xff01;好的&#xff0c;干货马上就来&#xff01; 初识vim 在讲解vim之前&#xff0c;我们首先要了解vim是什么&#xff0c;有什么作用&#xff1f;只有了解了vim才能更好的理…

腾讯云3年540,买其他服务器的都是韭菜!

你是否曾经为选择一款合适的云服务器而烦恼&#xff1f;市场上的云服务器品牌繁多&#xff0c;价格各异&#xff0c;如何才能找到一款性价比高&#xff0c;又适合自己的服务器呢&#xff1f;今天&#xff0c;我要给大家介绍一款腾讯云服务器&#xff0c;3年只需540元&#xff0…

Pow(x, n)

题目链接 Pow(x, n) 题目描述 注意点 n 是一个整数要么 x 不为零&#xff0c;要么 n > 0-100.0 < x < 100.0 解答思路 完成x的n次方的功能 代码 class Solution {public double myPow(double x, int n) {long N n;return N > 0 ? quickMul(x, N) : 1.0 / …

性价比高的照明品牌,五款经济实惠的照明品牌推荐

很多家长有时候会说孩子觉得家里的台灯灯光刺眼&#xff0c;看书看久了就不舒服。这不仅要看光线亮度是否柔和&#xff0c;还要考虑台灯是不是有做遮光式设计。没有遮光式设计的台灯&#xff0c;光源外露&#xff0c;灯光会直射孩子头部&#xff0c;孩子视线较低&#xff0c;很…

c++移动构造函数

左值与右值 左值&#xff1a;能用取址符号 & 取出地址的值右值&#xff1a;不能用取值符合取出地址的值&#xff0c;如临时对象 int i 1; // i 是左值&#xff0c;1 是右值int GetZero {int zero 0&#xff1b;return zero; } //j 是左值&#xff0c;GetZero() 是右值&…