json字符串转为开闭区间

news2025/1/10 20:33:02

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);
    }

}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Unity细节】VS不能附加到Unity程序中解决方法大全

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! 本文由 秩沅 原创 &#x1f636;‍&#x1f32b;️收录于专栏&#xff1a;unity细节和bug &#x1f636;‍&#x1f32b;️优质专栏 ⭐【…

Socks5代理怎么样?安全性高吗?

Socks5代理IP的安全性取决于多个因素&#xff0c;包括代理服务器的信任度、代理提供商的可靠性以及你在使用代理时的需要注意一些动作。 下面分享一些关于Socks5代理IP安全性的重要考虑因素&#xff1a; 1. 代理服务器的信任度&#xff1a;使用代理时&#xff0c;您要确保选择信…

【笔记】原型和原型链(持续完善)

概念 原型&#xff1a;函数都具有 prototype 属性&#xff0c;称之为原型&#xff0c;也称之为原型对象 1.1 原型可以放一些属性和方法&#xff0c;共享给实例对象使用&#xff08;也就是原生方法&#xff09;。 1.2 原型可以做继承原型链&#xff1a;对象都有 __proto__ 属性…

「Verilog学习笔记」多功能数据处理器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 分析 注意题目要求输入信号为有符号数&#xff0c;另外输出信号可能是输入信号的和&#xff0c;所以需要拓展一位&#xff0c;防止溢出。 timescale 1ns/1ns module data_…

HR人才测评,采用线上测评做春招秋招

从人力资源管理的工作&#xff0c;已经有好些年了&#xff0c;我只想说这不是一个有创意和创造性的工作&#xff0c;因为大部分时间我都在从事数据方面的工作。关于公司内部的文案工作先且不说&#xff0c;这里分享下我做招聘工作的过程。 每年春秋两季的校招&#xff0c;算是…

安防监控EasyCVR视频汇聚平台使用海康SDK播放时,画面播放缓慢该如何解决?

视频云存储/安防监控EasyCVR视频汇聚平台基于云边端智能协同&#xff0c;支持海量视频的轻量化接入与汇聚、转码与处理、全网智能分发、视频集中存储等。安防视频平台EasyCVR拓展性强&#xff0c;视频能力丰富&#xff0c;具体可实现视频监控直播、视频轮播、视频录像、云存储、…

MySQL数据库调优策略

1. 数据库调优的措施 1.1 调优的目标 尽可能节省系统资源&#xff0c;以便系统可以提供更大负荷的服务。&#xff08;吞吐量更大&#xff09; 合理的结构设计和参数调整&#xff0c;以提高用户操作 响应的速度。&#xff08;响应速度更快&#xff09; 减少系统的瓶颈&#xff0…

抽象工厂模式 rust和java的实现

文章目录 抽象工厂模式介绍抽象工厂模式包含以下几个核心角色&#xff1a;实现架构图java实现rust实现rust代码仓库 抽象工厂模式 抽象工厂模式&#xff08;Abstract Factory Pattern&#xff09;是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。 在抽象工…

快速灵敏的Flink2

flink基础知识 TumblingEventTimeWindows 滚动开窗 package org.apache.flink.streaming.api.windowing.assigners;import org.apache.flink.annotation.PublicEvolving; import org.apache.flink.api.common.ExecutionConfig; import org.apache.flink.api.common.typeutils.…

快速了解什么是跳跃表(skip list)

什么是跳跃表&#xff08;skip list&#xff09; 跳跃表&#xff08;Skip List&#xff09;是一种概率性的数据结构&#xff0c;它通过在多层链表的基础上添加“快速通道”来提高搜索效率。跳跃表的效率可以与平衡树相媲美&#xff0c;即在平均和最坏的情况下&#xff0c;查找…

alibaba店铺所有商品数据接口(alibaba.item_search_shop)

阿里巴巴店铺的所有商品数据接口&#xff08;item_search_shop&#xff09;可以获取到店铺内所有商品的信息&#xff0c;包括产品的ID、SKU信息、价格、库存、图片等。这些数据可以用于构建各种业务场景&#xff0c;例如供应链管理、电商平台的价格比较、竞品分析、实时库存查询…

Java练习题一

韩顺平老师的Java练习题 大家可以尝试着做一做 package exer;public class Demo01 {public static void main(String[] args) {double total 100000d;int count0;while(true){if (total > 50000) {total total*0.95;count;}else if (total<50000){total total-1000;co…

最新Next 14快速上手基础部分

最新Next 14快速上手基础部分 最新的NEXT快速上手文档&#xff0c;2023.10.27 英文官网同步&#xff0c;版本Next14.0.0 本项目案例&#xff1a;GitHub地址&#xff0c;可以根据git回滚代码到对应知识&#xff0c;若有错误&#xff0c;欢迎指正&#xff01; 一、介绍 1.什么是…

Flink SQL TopN语句详解

TopN 定义&#xff08;⽀持 Batch\Streaming&#xff09;&#xff1a; TopN 对应离线数仓的 row_number()&#xff0c;使⽤ row_number() 对某⼀个分组的数据进⾏排序。 应⽤场景&#xff1a; 根据 某个排序 条件&#xff0c;计算 某个分组 下的排⾏榜数据。 SQL 语法标准&am…

如何利用JSON Schema校验JSON数据格式

最近笔者在工作中需要监控一批http接口&#xff0c;并对返回的JSON数据进行校验。正好之前在某前端大神的分享中得知这个神器的存在&#xff0c;调研一番之后应用在该项目中&#xff0c;并取得了不错的效果&#xff0c;特地在此分享给各位读者。<br style"box-sizing: …

Moco框架初探

一、简介 Moco是一个搭建模拟服务器的工具&#xff0c;其支持API和独立运行两种方式&#xff0c;前者通常在junit等测试框架中使用&#xff0c;后者则是通过运行一个jar包开启服务。 二、用途 主要用于实现mock技术 1、后端接口开发未完成情况下&#xff0c;通过moco模拟接…

JavaWeb课程复习资料——idea创建JDBC

1、创建空的Java Project 输入项目名称 空项目 2、引入jar包步骤 依次点击 File -> Project Structure&#xff08;快捷键 Ctrl Alt Shift s&#xff09;&#xff0c;点击Project Structure界面左侧的“Modules”如图&#xff1a; 在 【Dependencies】 标签界面下&…

C语言学习笔记之结构篇

C语言是一门结构化程序设计语言。在C语言看来&#xff0c;现实生活中的任何事情都可看作是三大结构或者三大结构的组合的抽象&#xff0c;即顺序&#xff0c;分支&#xff08;选择&#xff09;&#xff0c;循环。 所谓顺序就是一条路走到黑&#xff1b;生活中在很多事情上我们都…

MVCC中的可见性算法

在之前的文章 MVCC详解-CSDN博客中我们已经介绍过了MVCC的原理&#xff08;read viewundo log&#xff09;&#xff0c;今天来详细的说一下readview的匹配规则&#xff08;可见性算法&#xff09; 隔离级别在RC&#xff0c;RR的前提下 Read View是如何保证可见性判断的呢&#…

微服务-grpc

微服务 一、微服务&#xff08;microservices&#xff09; 近几年,微服这个词闯入了我们的视线范围。在百度与谷歌中随便搜一搜也有几千万条的结果。那么&#xff0c;什么是微服务 呢&#xff1f;微服务的概念是怎么产生的呢&#xff1f; 我们就来了解一下Go语言与微服务的千丝…