天天看點

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

需求場景

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

飄乙己: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);
    }

}      

最無節操的寫法

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

首先查到根節點,parent_id = 0

通過根節點id擷取到所有一級節點,parent_id = 1

遞歸擷取所有節點的子節點,然後調用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()方法挑選出根節點的那顆樹即可。