鍍金池/ 問答/HTML/ 二維數(shù)組加對應(yīng)關(guān)系轉(zhuǎn)換成樹形結(jié)構(gòu)的問題

二維數(shù)組加對應(yīng)關(guān)系轉(zhuǎn)換成樹形結(jié)構(gòu)的問題

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

希望通過源數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)換成目標(biāo)樹形結(jié)構(gòu),直接從人的角度可以拼出結(jié)果,但如何通過代碼實(shí)現(xiàn)轉(zhuǎn)換?請大家?guī)兔?,謝謝!

最終需要實(shí)現(xiàn)的語言 JS,其他語言也可以提供下代碼思路

目標(biāo)表格

clipboard.png

源數(shù)據(jù)結(jié)構(gòu)

1. 數(shù)據(jù) (表格原始數(shù)據(jù))

[
["報表測試","","","","","1"],
["單元格", "","跨行合并","指標(biāo)列","","2"],
["statis_date","公司","","太原","福州","4"]
]

2. 關(guān)系 (表示單元格的合并行和列的情況)

[
 { 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.說明

  • 關(guān)系中 col 代表 列序號, row 代表 行序號colspan 代表 跨列數(shù) ,rowspan 代表 跨行數(shù)
  • 合并不能僅依靠空數(shù)據(jù)就合并,需要根據(jù)關(guān)系進(jìn)行定位合并的位置,空可能也會單獨(dú)單元格顯示
  • 存在一條默認(rèn)的關(guān)系即,沒有在關(guān)系中標(biāo)識的單元格的關(guān)系即為 colspan 1 rowspan 1

目標(biāo)數(shù)據(jù)結(jié)構(gòu)

目標(biāo)數(shù)據(jù)中 層級 表示 行子元素表示下面的列內(nèi)容
需要實(shí)現(xiàn)行合并和列合并

[
    {
        "label": "報表測試",
        "children": [
            {
                "label": "單元格",
                "children": [
                    {
                        "label": "statis_date",
                        "children": []
                    },
                    {
                        "label": "公司",
                        "children": []
                    }
                ]
            },
            {
                "label": "跨行合并",
                "children": []
            },
            {
                "label": "指標(biāo)列",
                "children": [
                    {
                        "label": "太原",
                        "children": []
                    },
                    {
                        "label": "福州",
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "label": "1",
        "children": [
            {
                "label": "2",
                "children": [
                    {
                        "label": "4",
                        "children": []
                    }
                ]
            }
        ]
    }
]
回答
編輯回答
荒城

js版實(shí)現(xiàn)

1. 將關(guān)系數(shù)組補(bǔ)全

初始化數(shù)據(jù)變量

// 表數(shù)據(jù)
const header = [
["報表測試","","","","","1"],
["單元格", "","跨行合并","指標(biāo)列","","2"],
["statis_date","公司","","太原","福州","4"]
]

// 關(guān)系
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 },
]

將已知關(guān)系轉(zhuǎn)換為對象方便判斷其是否非默認(rèn)關(guān)系

// 已知非默認(rèn)關(guān)系 (即 colspan rowspan 有任何一個不為1)
const relObj = {}
for (let i = 0; i < rel.length; i += 1) {
  const item = rel[i]
  relObj[`${item.col}_`${item.row}`] = item
}

計算整個表格數(shù)組的橫縱長度

// 列數(shù) (有個前提,每行列數(shù)一致)
const colLength = header[0].length

// 行數(shù)
const rowLength = header.length

生成整個表每個單元格的關(guān)系,并保存單元格數(shù)據(jù)

// 整個表每個單元格的關(guān)系,并保存單元格數(shù)據(jù)
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. 從每行遍歷單元格生成每個節(jié)點(diǎn)

!TODO

2018年4月19日 23:09
編輯回答
別逞強(qiáng)

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\"],[\"單元格\", \"\",\"跨行合并\",\"指標(biāo)列\(zhòng)",\"\",\"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) {
                // 當(dāng)前為第一行
                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 + "]";
    }
    
    
}
2017年12月25日 12:33
編輯回答
墨小羽

不知道 關(guān)系 那一條有啥用,沒有那個也能映射結(jié)果。

2018年6月8日 08:13
編輯回答
卟乖

謝邀,直接 DFS 遍歷一遍即可。當(dāng)然,你的數(shù)據(jù)能生成樹的前提是每個項(xiàng)的中間不會對應(yīng)上一行某個項(xiàng)的開始。

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"],
  ["單元格", "","跨行合并","指標(biāo)列","","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, '  '))
2017年8月19日 03:07