飄乙己:List轉Tree有4種寫法!

孔乙己說:回字有四種寫法。

飄乙己也說,list轉tree也有4種寫法,你用的是哪種?

需求場景

有下面一張區域表,典型的樹形結構設計。

現前端需要後端返回樹形數據結構用於構造展示樹。

本篇文章我們就來介紹一下在這種場景下後端構建樹形數據結構,也就是通過list轉tree的4種寫法。

代碼實戰

  1. 首先我們根據數據庫結構創建實體對象
/**
 * 區域平臺
 * @author:Jam
 */

@Data
public class Platform {
    private String id;
    private String parentId;
    private String name;
    private String platformCode;
    private List<Platform> children;

    public Platform(String id, String platformCode,String parentId, String name) {
        this.id = id;
        this.parentId = parentId;
        this.name = name;
        this.platformCode = platformCode;
    }

}


  1. 爲了便於演示我們就不連接數據庫,而是直接使用Junit5的 @BeforeEach註解初始化一份結構數據。
public class PlatformTest {

    private final List<Platform> platformList = Lists.newArrayList();
    private ObjectMapper objectMapper = new ObjectMapper();

    @BeforeEach
    private void init(){
        Platform platform0 = new Platform("1","001","0","集團");
        Platform platform1 = new Platform("2","QYPT001","1","銷委會");
        Platform platform2 = new Platform("3","QYPT002","2","吉龍大區");
        Platform platform3 = new Platform("4","QYPT003","2","江蘇大區");
        Platform platform4 = new Platform("5","QYPT004","4","南京分區");

        Platform platform5 = new Platform("6","QYPT005","1","教育BG");
        Platform platform6 = new Platform("7","QYPT006","6","華南大區");
        Platform platform7 = new Platform("8","QYPT007","6","華東大區");

        platformList.add(platform0);
        platformList.add(platform1);
        platformList.add(platform2);
        platformList.add(platform3);
        platformList.add(platform4);
        platformList.add(platform5);
        platformList.add(platform6);
        platformList.add(platform7);
    }

}

最無節操的寫法

這種寫法毫無節操可言,全部通過數據庫遞歸查詢。

  1. 首先查到根節點,parent_id = 0
  2. 通過根節點id獲取到所有一級節點,parent_id = 1
  3. 遞歸獲取所有節點的子節點,然後調用setChildren()方法組裝數據結構。

具體寫法我就不展示了,辣眼睛。都2021年了我見過不止一次在項目中出現這種寫法。

雙重循環

這種寫法比較簡單,也是比較容易想到的。通過雙重循環確定父子節點的關係。

@SneakyThrows
@Test
public void test1(){
  System.out.println(platformList.size());
  List<Platform> result = Lists.newArrayList();
  for (Platform platform : platformList) {

    //獲取根節點
    if(platform.getParentId().equals("0")){
      result.add(platform);
    }

    for(Platform child : platformList){
      if(child.getParentId().equals(platform.getId())){
        platform.addChild(child);
      }
    }
  }

  System.out.println(objectMapper.writeValueAsString(result));
}

同時需要給Platform添加一個addChild()的方法。

public void addChild(Platform platform){
  if(children == null){
    children = new ArrayList<>();
  }
  children.add(platform);
}


雙重遍歷

第一次遍歷藉助hashmap存儲父節點與子節點的關係,第二次遍歷設置子節點,由於map中已經維護好了對應關係所以只需要從map取即可。

@SneakyThrows
@Test
public void test2(){
  Map<String, List<Platform>> platformMap = new HashMap<>();

  platformList.forEach(platform -> {
    List<Platform> children = platformMap.getOrDefault(platform.getParentId(), new ArrayList<>());
    children.add(platform);
    platformMap.put(platform.getParentId(),children);
  });

  platformList.forEach(platform -> platform.setChildren(platformMap.get(platform.getId())));

  List<Platform> result = platformList.stream().filter(v -> v.getParentId().equals("0")).collect(Collectors.toList());

  System.out.println(objectMapper.writeValueAsString(result));

}

Stream 分組

@SneakyThrows
@Test
public void test4(){
  Map<String, List<Platform>> groupMap = platformList.stream().collect(Collectors.groupingBy(Platform::getParentId));
  platformList.forEach(platform -> platform.setChildren(groupMap.get(platform.getId())));
  List<Platform> collect = platformList.stream()
    .filter(platform -> platform.getParentId().equals("0")).collect(Collectors.toList());
  System.out.println(objectMapper.writeValueAsString(collect));
}

此處主要通過Collectors.groupingBy(Platform::getParentId)方法對platformList按照parentId進行分組,分組後父節點相同的都放一起了。

然後再循環platformList,給其設置children屬性。

執行完成後已經形成了多顆樹,最後我們再通過filter()方法挑選出根節點的那顆樹即可。


< END >

往期精選:

SpringBoot 如何生成接口文檔,老鳥們都這麼玩的!

我們常說的數據庫優化,可以從哪些維度入手?

遇到線上問題不要慌,這些命令可以助你迅速定位(建議收藏)

SpringBoot 如何進行參數校驗?老鳥們都是這麼玩的!


更多精彩,點擊關注公衆號

本文分享自微信公衆號 - JAVA日知錄(javadaily)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章