JAVA合并单元格算法

1、适用于VXE-TABLE 前端表格的合并单元格算法:

/**
     * 纵向计算生成合并单元格配置
     * @param data 数据
     * @return [{ "row": 0, "col": 0, "rowspan": 0, "colspan": 1 }]
     */
    public static List<Map<String,Object>> mergeCells(List<Map<String,Object>> data) {
                List<Map<String,Object>> mergelist = new ArrayList<>();
                List<Map<String,Object>> mergelist2 = new ArrayList<>();
        // 多组列计算
        Map<Object,List<Map<String,Object>>> glist =data.stream().collect(Collectors.groupingBy(e -> e.get(Constant.RULE_TYPE),
                LinkedHashMap::new,Collectors.toList()));
        glist.forEach((key, list)->{
            // 逻辑梳理,rowspan为向下合并几行,
            // row 标记为向下合并从第几行开始,
            // 当第一次循环时,默认从0开始,当第n次循环时,n的row= (row(上次合并前起始位置)+ rowspan(上次向下合并了几行的结果))
            int row = mergelist.size() == 0 ? 0:
                    ((int)mergelist.get(mergelist.size()-1).get(Constant.ROWS) + (int)mergelist.get(mergelist.size()-1).get(Constant.ROWSPAN));
            Map<String,Object> mergeMap = createdMergeCell(row, 0, list.size(), 0);
            mergelist.add(mergeMap);
            // 第二列合并单元格
            Map<Object,List<Map<String,Object>>> child = list.stream().collect(Collectors.groupingBy(e -> e.get(Constant.SEC_NAME1),
                    LinkedHashMap::new,Collectors.toList()));
            child.forEach((childKey, childList)->{
                int childRow = mergelist2.size() == 0 ? 0:
                        ((int)mergelist2.get(mergelist2.size()-1).get(Constant.ROWS) + (int)mergelist2.get(mergelist2.size()-1).get(Constant.ROWSPAN));
                Map<String,Object> mergeMap2 = createdMergeCell(childRow, 1, childList.size(), 0);
                mergelist2.add(mergeMap2);
            });
        });
        mergelist.addAll(mergelist2);
        return mergelist;
    }

 /**
     * 生成合并单元格配置参数
     * @param row 从第几行开始
     * @param col  从第几列开始
     * @param rowspan 纵向合并几行
     * @param colspan 横向合并几列
     * @return
     */
    private static Map<String,Object> createdMergeCell(int row, int col, int rowspan, int colspan) {
        Map<String,Object> mergeMap = new HashMap<>();
        mergeMap.put(Constant.ROWS,row);
        mergeMap.put(Constant.COL,col);
        mergeMap.put(Constant.ROWSPAN,rowspan);
        mergeMap.put(Constant.COLSPAN,colspan);
        return mergeMap;
    }

2、POI 导出Excel 动态计算合并单元格算法:

/**
     * 纵向计算生成合并单元格配置
     * @param data 数据
     * @return [{ "row": 0, "col": 0, "rowspan": 0, "colspan": 1 }]
     */
    public  List<Map<String,Object>> mergeCells(List<Map<String,Object>> data) {
        int index = sheet.getLastRowNum() + 1; // 定义起始行
        List<Map<String,Object>> mergelist = new ArrayList<>();
        List<Map<String,Object>> mergelist2 = new ArrayList<>();
        List<Map<String,Object>> mergelist3 = new ArrayList<>();
        // 多组列计算
        Map<Object,List<Map<String,Object>>> glist =data.stream().collect(Collectors.groupingBy(e -> e.get(Constant.RULE_TYPE),
                LinkedHashMap::new,Collectors.toList()));
        int finalIndex = index;
        glist.forEach((key, list)->{
            /*
               逻辑梳理:
               finalIndex: 为excel的最后一行,这里为计算数据合并单元格,所以finalIndex需要+1 从excel最后一行的下一行开始计算
               firstCol和lastCol:程序需要excel纵向合并所以firstCol和lastCol 为相同值,代表不横向合并,比如值为0则操作ExcelA列,值为1则代表操作Excel0列
               这里用mergelist存A列纵向合并数据,mergelist2存B列纵向合并数据
               firstRow:
                    当mergelist集合中为空时,则说明为第一次循环,firstRow为表格最后一行+1(已经在程序进入前加过了),当第2+n次循环
                    firstRow的值为mergelist中最后一行的lastRow向下+1, 一次类推
                lastRow:
                    结束行下标,为计算后的firstRow + 当前循环的组内数据的长度-1
             */
            int firstRow0 = mergelist.size() == 0 ? finalIndex : (int)mergelist.get(mergelist.size()-1).get(Constant.LAST_ROW)+1;
            Map<String,Object> mergeMap = createdMergeCell(firstRow0, 0, firstRow0 + list.size()-1, 0);
            mergelist.add(mergeMap);
            /*
               第二列纵向合并单元格逻辑梳理:
               第二列的数据完全由第一列组内的数据,根据某个字段再次分组的来的,所以要在第一列组循环体内,进行再次分组,计算第二列的合并单元格
               合并单元格计算方式同上,需要一个新的集合 mergelist2 来存放组2的数据。firstCol和lastCol 置为1,操作Excel中B列。
             */
            Map<Object,List<Map<String,Object>>> child = list.stream().collect(Collectors.groupingBy(e -> e.get(Constant.SEC_NAME1),
                    LinkedHashMap::new,Collectors.toList()));
            child.forEach((childKey, childList)->{
                int firstRow1 = mergelist2.size() == 0 ? finalIndex :  (int)mergelist2.get(mergelist2.size()-1).get(Constant.LAST_ROW) + 1;
                Map<String,Object> mergeMap2 = createdMergeCell(firstRow1, 1, firstRow1 + childList.size() -1, 1);
                mergelist2.add(mergeMap2);
            });
        });
        mergelist.addAll(mergelist2);
        /*
          剔除无效数据:
          注意:
            处理纵向合并数据,由于纵向合并为动态计算的,poi导出Excel比较严谨,结束行必须大于开始行,否则会报错。
            以上循环体内无法操作,如只有一行数据,并不需要合并,
            但是需要其占位,存入mergelist中,便于下次循环能够准确获取上一行的lastRow 便于计算firstRow的值。
            这里将结束行小于等于开始行的数据统一剔除掉。
         */
        List<Map<String,Object>> merge = mergelist.stream().filter((item)->(int)item.get(Constant.FIRST_ROW) < (int)item.get(Constant.LAST_ROW)).collect(Collectors.toList());
        // 固定添加横向合并数据 Excel C列横向合并到D列
        for(int i =0; i<data.size(); i++) {
            Map<String,Object> mergeMap3 = createdMergeCell(index, 2, index, 4);
            mergelist3.add(mergeMap3);
            index++;
        }
        merge.addAll(mergelist3);
        return merge;
    }

addMerge(sheet.getLastRowNum() ,sheet.getLastRowNum(),1,4);
        // 2 动态设置数据合并单元格
        List<Map<String,Object>> mergeData = mergeCells(dataB);
        // 2.1 批量创建合并单元格
        for(Map merge : mergeData){
            addMerge((int)merge.get(Constant.FIRST_ROW),(int)merge.get(Constant.LAST_ROW),(int)merge.get(Constant.FIRST_COL),(int)merge.get(Constant.LAST_COL));
        }

/**
     * 添加合并单元格数据
     * @param firstRow  开始行 从0开始
     * @param lastRow   结束行 从0开始数,
     * @param firstCol  开始列 从0开始
     * @param lastCol   结束列 从0开始数
     */
    private void addMerge(int firstRow, int lastRow, int firstCol, int lastCol) {
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); // 标题
    }

3、VXE-TABLE 前端处理合并单元格算法:

https://vxetable.cn/v4/#/table/edit/span

		<vxe-table
          border
          show-overflow
          ref="xTable"
          height="500"
          :span-method="rowspanMethod"
          :data="tableData"
          :edit-rules="demo1.validRules"
          :edit-config="{trigger: 'click', mode: 'cell'}">
  // 通用行合并函数(将相同多列数据合并为一行)
            const rowspanMethod: VxeTablePropTypes.SpanMethod = ({ row, _rowIndex, column, visibleData }) => {
              const fields = ['role']
              const cellValue = row[column.field]
              if (cellValue && fields.includes(column.field)) {
                const prevRow = visibleData[_rowIndex - 1]
                let nextRow = visibleData[_rowIndex + 1]
                if (prevRow && prevRow[column.field] === cellValue) {
                  return { rowspan: 0, colspan: 0 }
                } else {
                  let countRowspan = 1
                  while (nextRow && nextRow[column.field] === cellValue) {
                    nextRow = visibleData[++countRowspan + _rowIndex]
                  }
                  if (countRowspan > 1) {
                    return { rowspan: countRowspan, colspan: 1 }
                  }
                }
              }
            }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值