多级序号列表实现

多级序号列表实现

编辑时间:20200927

背景

待排序数据是某份工作手册的条目,用户按照xxx.xxx.xxx…的形式输入,将会自动确定这条数据所在层级,并且会要求按照期望结果进行排序,这有些类似于word中的多级目录,但是因为数据的原因,直接对这部分进行排序,得不到期望结果,因为数据库是按照字符来进行排序的,所有我们需要在数据入库之前进行处理,让条目,能够正常排序

待排序数据期望结果实际排序结果
111
222
32.92.10
3.22.102.9
3.1.133
3.10.23.13.1
2.93.1.13.1.1
2.103.23.10.2
3.13.10.23.2

需求

  1. 用户输入xxx.xxx.xxx形式的数据,自动确认数据层级
  2. 每一级能够支持三位数字
  3. 能够满足多级序号(无限级)
  4. 能快速准确排序,并按照期望结果输出

方案

分析

  • 因为数据存在多个【.】所以数据库字段类型,只有设置为字符
  • 直接对字符排序,不能达到期望结果
  • 以MySQL为例,数据库会严格按照0-9的顺序进行排列,前提是他们都在同一个字符位置

数据拆分分析

数据拆分第一位第二位第三位第四位第五位第六位
1=>1
2=>2
3=>3
3.2=>3.2
3.1.1=>3.1.1
3.10.2=>3.10.2
2.9=>2.9
2.10=>2.10
3.1=>3.1

观察他们拆分后的位置,以及mysql字符排序的原则,不难理解,为什么达不到我们所期望的结果,
因为1一直会排在9前面,所以造成了2.10排在了2.9的前面,后面的数据也是因为这个原因错位了

解决方案

方案一

将每一个部分设计为一个字段,每个字段都为数字类型,然后按顺序进行排序,在显示的时候可以选择将每个字段进行拼接,也可以设计一个字段存放用户输入的数据

缺点

当前方案存在缺点,不能实现无限级的数据解析

方案二(推荐)

在用户输入数据后,对数据进行一遍处理(这里约定每一位最大值为999,所以将每一位的数据处理为000的形式,如果每一位最大值为9999,可以将数据处理为0000,五位,六位以此类推)

用户输入数据处理结果
1=>001
2=>002
3=>003
3.2=>003002
3.1.1=>003001001
3.10.2=>003010002
2.9=>002009
2.10=>002010
3.1=>003001

对处理后的数据,进行拆分,可以得到如下结果(空数据可以看做为0),排序的时候,数据库会对每一位从0到9依次排序

数据拆分第一位第二位第三位第四位第五位第六位第七位第八位第九位
001=>001
002=>002
003=>003
003002=>003002
003001001=>003001001
003010002=>003010002
002009=>002009
002010=>002010
003001=>003001

这样处理过后,对处理后的数据进行排序,就能得到我们想要的输出结果,这样的处理方式,在理论上就能实现无限级的排序,处理后的数据,可以在后面进行一个补0的操作,但是我们不确定到底有多少层级,所有我们不进行补齐,依然可以实现(补齐只是数据看起来好看一些)

实现

实现部分,主要是对用户输入数据,进行格式化,实现方式很多,现在列举一种

/**
 * <p>
 * 处理序号,对用户输入的序号进行转换
 * <pre>
 *     1        =>      001
 *     1.1      =>      001001
 *     23.2     =>      023002
 *     3.4.15.3 =>      003004015003
 * </pre>
 * </p>
 *
 * @param serialNum : 用户输入的序号
 * @return {@link String} 处理后的序号 (1.2.13.111)001002013111
 * @author wangyihuai
 * @date 2020/09/29 下午 03:26
 */
public String parseSerial(String serialNum) {
    //格式化
    DecimalFormat decimalFormat = new DecimalFormat("000");
    //按照【.】将数据进行分割
    String[] serials = serialNum.split("\\.");
    StringBuilder builder = new StringBuilder();
    for (String serial : serials) {
        //限定每一个节点只能输入三位
        if (serial.length() > 3) {
            //TODO 异常处理
        } else {
            //将格式化后的数据,进行拼接
            builder.append(decimalFormat.format(Integer.valueOf(serial)));
        }
    }
    return builder.toString();
}

写在最后

第二种解决方案可以用在很多有多级数据排序的地方,

例:

  1. 电商经常会用到的面包屑(分类)
  2. 省市区
  3. 多级目录
  4. 部门树
  5. ……

上诉场景,除了会有pid记录层级关系,还会有一个字段记录当前数据的层级关系(例如:001/002/003),一般有多级树(三级或三级以上)的需求都会用这种方式进行实现

本文中的数据,需要排序,所以没有加分隔符,省市区,部门等需求一般会让用户指定顺序,所以记录层级关系的字段,也只是用来快速定位的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值