返回列表 上一筆 下一筆

📄 資料內容

import java.util.*;



public class TreeUtils {



    /** 先前的建樹:用 iftPrev 串接父子,回傳所有 root 清單 */

    public static List<TreeNodeBean> buildTree(List<TreeNodeBean> flatList) {

        Map<String, TreeNodeBean> lookup = new HashMap<>();

        for (TreeNodeBean node : flatList) {

            lookup.put(node.getIftSid(), node);

            node.setChildren(new ArrayList<>()); // 確保 not null

        }



        List<TreeNodeBean> roots = new ArrayList<>();

        for (TreeNodeBean node : flatList) {

            String parentId = node.getIftPrev();

            if (parentId == null || parentId.isBlank() || "0".equals(parentId)) {

                roots.add(node);

            } else {

                TreeNodeBean parent = lookup.get(parentId);

                if (parent != null) parent.getChildren().add(node);

                else roots.add(node); // 找不到父節點就先視為 root

            }

        }

        return roots;

    }



    /** 建立 id → node 的索引(之後取路徑、檢核都會用到) */

    public static Map<String, TreeNodeBean> buildIndex(List<TreeNodeBean> flatList) {

        Map<String, TreeNodeBean> map = new HashMap<>();

        for (TreeNodeBean n : flatList) map.put(n.getIftSid(), n);

        return map;

    }



    /** 從 root 到當前節點的「ID 路徑」;includeSelf 決定是否包含自己 */

    public static List<String> getPathIdsFromRoot(TreeNodeBean node,

                                                  Map<String, TreeNodeBean> byId,

                                                  boolean includeSelf) {

        Deque<String> stack = new ArrayDeque<>();

        // 先把祖先一路往上塞進前面

        String p = node.getIftPrev();

        while (p != null && !p.isBlank() && !"0".equals(p)) {

            stack.addFirst(p);

            TreeNodeBean parent = byId.get(p);

            if (parent == null) break; // 資料不完整就停

            p = parent.getIftPrev();

        }

        // 需要時把自己加到最後

        if (includeSelf) stack.addLast(node.getIftSid());

        return new ArrayList<>(stack);

    }



    /** 取「名稱路徑」:從 root → ... → 自己(方便顯示) */

    public static List<String> getPathNamesFromRoot(TreeNodeBean node,

                                                    Map<String, TreeNodeBean> byId,

                                                    boolean includeSelf) {

        List<String> ids = getPathIdsFromRoot(node, byId, includeSelf);

        List<String> names = new ArrayList<>(ids.size());

        for (String id : ids) {

            TreeNodeBean x = byId.get(id);

            names.add(x != null ? x.getFtName() : ("#" + id));

        }

        return names;

    }



    /** 檢核 sft_path:\3808\3811\3813\ 需等於實際祖先鏈(不含自己) */

    public static boolean validateSftPath(TreeNodeBean node, Map<String, TreeNodeBean> byId) {

        // 解析原始 path

        List<String> expected = parsePathIds(node.getFtPathRaw());

        // 實際父鏈(不含自己)

        List<String> actual = getPathIdsFromRoot(node, byId, false);

        return expected.equals(actual);

    }



    /** 把 "\\3808\\3811\\3813\\" 解析成 ["3808","3811","3813"];容忍前後沒有反斜線 */

    public static List<String> parsePathIds(String raw) {

        if (raw == null) return List.of();

        String s = raw.trim();

        if (s.startsWith("\\")) s = s.substring(1);

        if (s.endsWith("\\")) s = s.substring(0, s.length() - 1);

        if (s.isEmpty()) return List.of();

        return Arrays.asList(s.split("\\\\"));

    }



    /** 簡單印樹(檢查用) */

    public static void printTree(List<TreeNodeBean> nodes, int level) {

        for (TreeNodeBean n : nodes) {

            System.out.println("  ".repeat(level) + n.getIftSid() + " " + n.getFtName());

            if (n.getChildren() != null && !n.getChildren().isEmpty()) {

                printTree(n.getChildren(), level + 1);

            }

        }

    }

}

🔐 Base64 編碼內容

aW1wb3J0IGphdmEudXRpbC4qOwoKCgpwdWJsaWMgY2xhc3MgVHJlZVV0aWxzIHsKCgoKICAgIC8qKiDlhYjliY3nmoTlu7rmqLnvvJrnlKggaWZ0UHJldiDkuLLmjqXniLblrZDvvIzlm57lgrPmiYDmnIkgcm9vdCDmuIXllq4gKi8KCiAgICBwdWJsaWMgc3RhdGljIExpc3Q8VHJlZU5vZGVCZWFuPiBidWlsZFRyZWUoTGlzdDxUcmVlTm9kZUJlYW4+IGZsYXRMaXN0KSB7CgogICAgICAgIE1hcDxTdHJpbmcsIFRyZWVOb2RlQmVhbj4gbG9va3VwID0gbmV3IEhhc2hNYXA8PigpOwoKICAgICAgICBmb3IgKFRyZWVOb2RlQmVhbiBub2RlIDogZmxhdExpc3QpIHsKCiAgICAgICAgICAgIGxvb2t1cC5wdXQobm9kZS5nZXRJZnRTaWQoKSwgbm9kZSk7CgogICAgICAgICAgICBub2RlLnNldENoaWxkcmVuKG5ldyBBcnJheUxpc3Q8PigpKTsgLy8g56K65L+dIG5vdCBudWxsCgogICAgICAgIH0KCgoKICAgICAgICBMaXN0PFRyZWVOb2RlQmVhbj4gcm9vdHMgPSBuZXcgQXJyYXlMaXN0PD4oKTsKCiAgICAgICAgZm9yIChUcmVlTm9kZUJlYW4gbm9kZSA6IGZsYXRMaXN0KSB7CgogICAgICAgICAgICBTdHJpbmcgcGFyZW50SWQgPSBub2RlLmdldElmdFByZXYoKTsKCiAgICAgICAgICAgIGlmIChwYXJlbnRJZCA9PSBudWxsIHx8IHBhcmVudElkLmlzQmxhbmsoKSB8fCAiMCIuZXF1YWxzKHBhcmVudElkKSkgewoKICAgICAgICAgICAgICAgIHJvb3RzLmFkZChub2RlKTsKCiAgICAgICAgICAgIH0gZWxzZSB7CgogICAgICAgICAgICAgICAgVHJlZU5vZGVCZWFuIHBhcmVudCA9IGxvb2t1cC5nZXQocGFyZW50SWQpOwoKICAgICAgICAgICAgICAgIGlmIChwYXJlbnQgIT0gbnVsbCkgcGFyZW50LmdldENoaWxkcmVuKCkuYWRkKG5vZGUpOwoKICAgICAgICAgICAgICAgIGVsc2Ugcm9vdHMuYWRkKG5vZGUpOyAvLyDmib7kuI3liLDniLbnr4Dpu57lsLHlhYjoppbngrogcm9vdAoKICAgICAgICAgICAgfQoKICAgICAgICB9CgogICAgICAgIHJldHVybiByb290czsKCiAgICB9CgoKCiAgICAvKiog5bu656uLIGlkIOKGkiBub2RlIOeahOe0ouW8le+8iOS5i+W+jOWPlui3r+W+keOAgeaqouaguOmDveacg+eUqOWIsO+8iSAqLwoKICAgIHB1YmxpYyBzdGF0aWMgTWFwPFN0cmluZywgVHJlZU5vZGVCZWFuPiBidWlsZEluZGV4KExpc3Q8VHJlZU5vZGVCZWFuPiBmbGF0TGlzdCkgewoKICAgICAgICBNYXA8U3RyaW5nLCBUcmVlTm9kZUJlYW4+IG1hcCA9IG5ldyBIYXNoTWFwPD4oKTsKCiAgICAgICAgZm9yIChUcmVlTm9kZUJlYW4gbiA6IGZsYXRMaXN0KSBtYXAucHV0KG4uZ2V0SWZ0U2lkKCksIG4pOwoKICAgICAgICByZXR1cm4gbWFwOwoKICAgIH0KCgoKICAgIC8qKiDlvp4gcm9vdCDliLDnlbbliY3nr4Dpu57nmoTjgIxJRCDot6/lvpHjgI3vvJtpbmNsdWRlU2VsZiDmsbrlrprmmK/lkKbljIXlkKvoh6rlt7EgKi8KCiAgICBwdWJsaWMgc3RhdGljIExpc3Q8U3RyaW5nPiBnZXRQYXRoSWRzRnJvbVJvb3QoVHJlZU5vZGVCZWFuIG5vZGUsCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hcDxTdHJpbmcsIFRyZWVOb2RlQmVhbj4gYnlJZCwKCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9vbGVhbiBpbmNsdWRlU2VsZikgewoKICAgICAgICBEZXF1ZTxTdHJpbmc+IHN0YWNrID0gbmV3IEFycmF5RGVxdWU8PigpOwoKICAgICAgICAvLyDlhYjmiornpZblhYjkuIDot6/lvoDkuIrloZ7pgLLliY3pnaIKCiAgICAgICAgU3RyaW5nIHAgPSBub2RlLmdldElmdFByZXYoKTsKCiAgICAgICAgd2hpbGUgKHAgIT0gbnVsbCAmJiAhcC5pc0JsYW5rKCkgJiYgISIwIi5lcXVhbHMocCkpIHsKCiAgICAgICAgICAgIHN0YWNrLmFkZEZpcnN0KHApOwoKICAgICAgICAgICAgVHJlZU5vZGVCZWFuIHBhcmVudCA9IGJ5SWQuZ2V0KHApOwoKICAgICAgICAgICAgaWYgKHBhcmVudCA9PSBudWxsKSBicmVhazsgLy8g6LOH5paZ5LiN5a6M5pW05bCx5YGcCgogICAgICAgICAgICBwID0gcGFyZW50LmdldElmdFByZXYoKTsKCiAgICAgICAgfQoKICAgICAgICAvLyDpnIDopoHmmYLmioroh6rlt7HliqDliLDmnIDlvowKCiAgICAgICAgaWYgKGluY2x1ZGVTZWxmKSBzdGFjay5hZGRMYXN0KG5vZGUuZ2V0SWZ0U2lkKCkpOwoKICAgICAgICByZXR1cm4gbmV3IEFycmF5TGlzdDw+KHN0YWNrKTsKCiAgICB9CgoKCiAgICAvKiog5Y+W44CM5ZCN56ix6Lev5b6R44CN77ya5b6eIHJvb3Qg4oaSIC4uLiDihpIg6Ieq5bex77yI5pa55L6/6aGv56S677yJICovCgogICAgcHVibGljIHN0YXRpYyBMaXN0PFN0cmluZz4gZ2V0UGF0aE5hbWVzRnJvbVJvb3QoVHJlZU5vZGVCZWFuIG5vZGUsCgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWFwPFN0cmluZywgVHJlZU5vZGVCZWFuPiBieUlkLAoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJvb2xlYW4gaW5jbHVkZVNlbGYpIHsKCiAgICAgICAgTGlzdDxTdHJpbmc+IGlkcyA9IGdldFBhdGhJZHNGcm9tUm9vdChub2RlLCBieUlkLCBpbmNsdWRlU2VsZik7CgogICAgICAgIExpc3Q8U3RyaW5nPiBuYW1lcyA9IG5ldyBBcnJheUxpc3Q8PihpZHMuc2l6ZSgpKTsKCiAgICAgICAgZm9yIChTdHJpbmcgaWQgOiBpZHMpIHsKCiAgICAgICAgICAgIFRyZWVOb2RlQmVhbiB4ID0gYnlJZC5nZXQoaWQpOwoKICAgICAgICAgICAgbmFtZXMuYWRkKHggIT0gbnVsbCA/IHguZ2V0RnROYW1lKCkgOiAoIiMiICsgaWQpKTsKCiAgICAgICAgfQoKICAgICAgICByZXR1cm4gbmFtZXM7CgogICAgfQoKCgogICAgLyoqIOaqouaguCBzZnRfcGF0aO+8mlwzODA4XDM4MTFcMzgxM1wg6ZyA562J5pa85a+m6Zqb56WW5YWI6Y+I77yI5LiN5ZCr6Ieq5bex77yJICovCgogICAgcHVibGljIHN0YXRpYyBib29sZWFuIHZhbGlkYXRlU2Z0UGF0aChUcmVlTm9kZUJlYW4gbm9kZSwgTWFwPFN0cmluZywgVHJlZU5vZGVCZWFuPiBieUlkKSB7CgogICAgICAgIC8vIOino+aekOWOn+WniyBwYXRoCgogICAgICAgIExpc3Q8U3RyaW5nPiBleHBlY3RlZCA9IHBhcnNlUGF0aElkcyhub2RlLmdldEZ0UGF0aFJhdygpKTsKCiAgICAgICAgLy8g5a+m6Zqb54i26Y+I77yI5LiN5ZCr6Ieq5bex77yJCgogICAgICAgIExpc3Q8U3RyaW5nPiBhY3R1YWwgPSBnZXRQYXRoSWRzRnJvbVJvb3Qobm9kZSwgYnlJZCwgZmFsc2UpOwoKICAgICAgICByZXR1cm4gZXhwZWN0ZWQuZXF1YWxzKGFjdHVhbCk7CgogICAgfQoKCgogICAgLyoqIOaKiiAiXFwzODA4XFwzODExXFwzODEzXFwiIOino+aekOaIkCBbIjM4MDgiLCIzODExIiwiMzgxMyJd77yb5a655b+N5YmN5b6M5rKS5pyJ5Y+N5pac57eaICovCgogICAgcHVibGljIHN0YXRpYyBMaXN0PFN0cmluZz4gcGFyc2VQYXRoSWRzKFN0cmluZyByYXcpIHsKCiAgICAgICAgaWYgKHJhdyA9PSBudWxsKSByZXR1cm4gTGlzdC5vZigpOwoKICAgICAgICBTdHJpbmcgcyA9IHJhdy50cmltKCk7CgogICAgICAgIGlmIChzLnN0YXJ0c1dpdGgoIlxcIikpIHMgPSBzLnN1YnN0cmluZygxKTsKCiAgICAgICAgaWYgKHMuZW5kc1dpdGgoIlxcIikpIHMgPSBzLnN1YnN0cmluZygwLCBzLmxlbmd0aCgpIC0gMSk7CgogICAgICAgIGlmIChzLmlzRW1wdHkoKSkgcmV0dXJuIExpc3Qub2YoKTsKCiAgICAgICAgcmV0dXJuIEFycmF5cy5hc0xpc3Qocy5zcGxpdCgiXFxcXCIpKTsKCiAgICB9CgoKCiAgICAvKiog57Ch5Zau5Y2w5qi577yI5qqi5p+l55So77yJICovCgogICAgcHVibGljIHN0YXRpYyB2b2lkIHByaW50VHJlZShMaXN0PFRyZWVOb2RlQmVhbj4gbm9kZXMsIGludCBsZXZlbCkgewoKICAgICAgICBmb3IgKFRyZWVOb2RlQmVhbiBuIDogbm9kZXMpIHsKCiAgICAgICAgICAgIFN5c3RlbS5vdXQucHJpbnRsbigiICAiLnJlcGVhdChsZXZlbCkgKyBuLmdldElmdFNpZCgpICsgIiAiICsgbi5nZXRGdE5hbWUoKSk7CgogICAgICAgICAgICBpZiAobi5nZXRDaGlsZHJlbigpICE9IG51bGwgJiYgIW4uZ2V0Q2hpbGRyZW4oKS5pc0VtcHR5KCkpIHsKCiAgICAgICAgICAgICAgICBwcmludFRyZWUobi5nZXRDaGlsZHJlbigpLCBsZXZlbCArIDEpOwoKICAgICAgICAgICAgfQoKICAgICAgICB9CgogICAgfQoKfQo=
返回列表 上一筆 下一筆