二维数组加对应关系转换成树形结构的问题

石墨文档:https://shimo.im/docs/h2J6PUv...

希望通过源数据结构转换成目标树形结构,直接从人的角度可以拼出结果,但如何通过代码实现转换?请大家帮忙,谢谢!

最终需要实现的语言 JS,其他语言也可以提供下代码思路

目标表格

clipboard.png

源数据结构

1. 数据 (表格原始数据)

[
["报表测试","","","","","1"],
["单元格", "","跨行合并","指标列","","2"],
["statis_date","公司","","太原","福州","4"]
]

2. 关系 (表示单元格的合并行和列的情况)

[
 { col: 0, colspan: 5, row: 0, rowspan: 1 },
 { col: 0, colspan: 2, row: 1, rowspan: 1 },
 { col: 2, colspan: 1, row: 1, rowspan: 2 },
 { col: 3, colspan: 2, row: 1, rowspan: 1 },
]

3.说明

  • 关系中 col 代表 列序号row 代表 行序号colspan 代表 跨列数rowspan 代表 跨行数
  • 合并不能仅依靠空数据就合并,需要根据关系进行定位合并的位置,空可能也会单独单元格显示
  • 存在一条默认的关系即,没有在关系中标识的单元格的关系即为 colspan 1 rowspan 1

目标数据结构

目标数据中 层级 表示 行子元素表示下面的列内容
需要实现行合并和列合并

[
    {
        "label": "报表测试",
        "children": [
            {
                "label": "单元格",
                "children": [
                    {
                        "label": "statis_date",
                        "children": []
                    },
                    {
                        "label": "公司",
                        "children": []
                    }
                ]
            },
            {
                "label": "跨行合并",
                "children": []
            },
            {
                "label": "指标列",
                "children": [
                    {
                        "label": "太原",
                        "children": []
                    },
                    {
                        "label": "福州",
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "label": "1",
        "children": [
            {
                "label": "2",
                "children": [
                    {
                        "label": "4",
                        "children": []
                    }
                ]
            }
        ]
    }
]
阅读 4.5k
4 个回答

谢邀,直接 DFS 遍历一遍即可。当然,你的数据能生成树的前提是每个项的中间不会对应上一行某个项的开始。

function genTree (data, relations) {

  const relationMap = relations.reduce((map, rel) => map.set(`${rel.row},${rel.col}`, rel), new Map())

  const root = []

  _gen(root, data, 0, 0, data[0].length, relationMap)

  return root

  function _gen (children, data, row, colStart, colEnd, relationMap) {
    if (row >= data.length) { return }

    for (let col = colStart; col < colEnd;) {
      const lastSameHeadRel = relationMap.get(`${row - 1},${col}`)
      if (lastSameHeadRel && lastSameHeadRel.row + lastSameHeadRel.rowspan > row) {
        // 跨行占位
        col += lastSameHeadRel.colspan
        break
      }

      let child = {
        label: data[row][col],
        children: []
      }

      children.push(child)

      const relation = relationMap.get(`${row},${col}`)
      const nextRow = row + (relation ? relation.rowspan : 1)
      const nextColStart = col
      const nextColEnd = col + (relation ? relation.colspan : 1)
      _gen(child.children, data, nextRow, nextColStart, nextColEnd, relationMap)

      col = nextColEnd
    }
  }
}
const data = [
  ["报表测试","","","","","1"],
  ["单元格", "","跨行合并","指标列","","2"],
  ["statis_date","公司","","太原","福州","4"]
]

const relations = [
  { col: 0, colspan: 5, row: 0, rowspan: 1 },
  { col: 0, colspan: 2, row: 1, rowspan: 1 },
  { col: 2, colspan: 1, row: 1, rowspan: 2 },
  { col: 3, colspan: 2, row: 1, rowspan: 1 },
]

console.log(JSON.stringify(genTree(data, relations), null, '  '))

Node.java

public class Node {
    String label;
    List<Node> children = new ArrayList<Node>();

    int col;
    int colspan;
    int row;
    int rowspan;

    public String getLabel() {
        return label;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List<Node> getChildren() {
        return children;
    }

    public void setChildren(List<Node> children) {
        this.children = children;
    }

    @Override
    public String toString() {
        return "Node [label=" + label + ", children=" + children + "]";
    }

    public static void main(String[] args) {
        String oldData = "[[\"报表测试\",\"\",\"\",\"\",\"\",\"1\"],[\"单元格\", \"\",\"跨行合并\",\"指标列\",\"\",\"2\"],[\"statis_date\",\"公司\",\"\",\"太原\",\"福州\",\"4\"]]";
        String struct = "[{col:0,colspan:5,row:0,rowspan:1},{col:5,colspan:1,row:0,rowspan:1},{col:0,colspan:2,row:1,rowspan:1},{col:2,colspan:1,row:1,rowspan:2},{col:3,colspan:2,row:1,rowspan:1},{col:5,colspan:1,row:1,rowspan:1},{col:0,colspan:1,row:2,rowspan:1},{col:1,colspan:1,row:2,rowspan:1},    {col:3,colspan:1,row:2,rowspan:1},    {col:4,colspan:1,row:2,rowspan:1},    {col:5,colspan:1,row:2,rowspan:1}    ]";
        List<Struct> structs = JSONArray.parseArray(struct, Struct.class);
        List<List<Node>> nodeArray = new ArrayList<List<Node>>();
        for (int i = 0; i < structs.size(); i++) {
            nodeArray.add(new ArrayList<Node>());
        }
        System.err.println(structs);
        JSONArray jsonArray = (JSONArray) JSONArray.parse(oldData);
        List<Node> root = new ArrayList<Node>();
        int row = 0;
        for (Struct structItem : structs) {
            Node node = new Node();
            JSONArray jsonArray2 = (com.alibaba.fastjson.JSONArray) jsonArray.get(structItem.getRow());
            String label = jsonArray2.getString(structItem.getCol());
            node.setLabel(label);
            node.col = structItem.getCol();
            node.colspan = structItem.getColspan();
            node.row = structItem.getRow();
            node.rowspan = structItem.getRowspan();
            row = structItem.row;
            if (row == 0) {
                // 当前为第一行
                root.add(node);
                row = structItem.getRow();

            } else {
                for (Node node2 : nodeArray.get(structItem.row - 1)) {
                    if (node2.col <= structItem.getCol() && structItem.getCol() < node2.col + node2.colspan) {
                        node2.getChildren().add(node);
                        break;
                    }
                }
                
            }
            nodeArray.get(row).add(node);
        }
        System.err.println(JSONArray.toJSON(root));

    }
}

Struct.java


public class Struct {
    int col;
    int colspan;
    int row;
    int rowspan;
    public int getCol() {
        return col;
    }
    public void setCol(int col) {
        this.col = col;
    }
    public int getColspan() {
        return colspan;
    }
    public void setColspan(int colspan) {
        this.colspan = colspan;
    }
    public int getRow() {
        return row;
    }
    public void setRow(int row) {
        this.row = row;
    }
    public int getRowspan() {
        return rowspan;
    }
    public void setRowspan(int rowspan) {
        this.rowspan = rowspan;
    }
    @Override
    public String toString() {
        return "Struct [col=" + col + ", colspan=" + colspan + ", row=" + row + ", rowspan=" + rowspan + "]";
    }
    
    
}

js版实现

1. 将关系数组补全

初始化数据变量

// 表数据
const header = [
["报表测试","","","","","1"],
["单元格", "","跨行合并","指标列","","2"],
["statis_date","公司","","太原","福州","4"]
]

// 关系
const relation = [
 { col: 0, colspan: 5, row: 0, rowspan: 1 },
 { col: 0, colspan: 2, row: 1, rowspan: 1 },
 { col: 2, colspan: 1, row: 1, rowspan: 2 },
 { col: 3, colspan: 2, row: 1, rowspan: 1 },
]

将已知关系转换为对象方便判断其是否非默认关系

// 已知非默认关系 (即 colspan rowspan 有任何一个不为1)
const relObj = {}
for (let i = 0; i < rel.length; i += 1) {
  const item = rel[i]
  relObj[`${item.col}_`${item.row}`] = item
}

计算整个表格数组的横纵长度

// 列数 (有个前提,每行列数一致)
const colLength = header[0].length

// 行数
const rowLength = header.length

生成整个表每个单元格的关系,并保存单元格数据

// 整个表每个单元格的关系,并保存单元格数据
const relArr= []
for (let i = 0; i < rowLength; i += 1) {
  const row = i
  for (let j = 0; j < colLength; j += 1) {
    const col = j
    if (relObj[col + '_' + row]) {
      const obj = relObj[col + '_' + row]
       relArr.push({
       label: header[row][col],
       col: col,
       row: row,
       colspan: obj.colspan,
       rowspan: obj.rowspan
      })
    } else {
      relArr.push({
        label: header[row][col],
        col: col,
        row: row,
        colspan: 1,
        rowspan: 1,
    })
  }
  }
}

2. 从每行遍历单元格生成每个节点

!TODO

不知道 关系 那一条有啥用,没有那个也能映射结果。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题