Construct data with parent-child structure into tree structure data, support multiple root nodes

In daily projects, data with a parent-child structure is often structured into tree structure data, such as organizational data. I have seen many solutions on the Internet before and found that the structured tree structure data field is a encapsulated specific class. If you want to add other return fields, you need to add fields to the class yourself. So I implemented a set of solutions through generics on the basis of your predecessors, and supported custom root node judgments. 

The class that needs to be converted into a tree structure needs to implement this interface, and the generic T is the entity class type 
public interface ITreeNode<T> { 

   Object id(); 

   Object parentId(); 

   void addChild(T t); 

   void removeChild(T t ); 

   List<T> children(); 
}

 

The functional interface is used to determine the root node, there is a default judgment, of course, you can also customize the implementation. The default root node judgment method is that parentId is null, or parentId is equal to the given value, and the given value can be passed in.

@FunctionalInterface
public interface TreePredicate<T,R> {
    boolean test(T t, R r);

    static <T extends ITreeNode,R> TreePredicate<T ,R> rootNodePredicate(){
        return (T t,R r)->t.parentId() == null || t.parentId().equals(r);
    }
}

 

This class is the class that constructs the tree structure, the core method TreeBuilder(List<T> list, TreePredicate<T,R> predicate, R r) constructor, the core idea is to pass by reference

public class TreeBuilder<T extends ITreeNode<T>> { 
    private final LinkedHashMap<Object, T> treeNodesMap = new LinkedHashMap<>(); 
    private final List<T> rootNodesList = new ArrayList<>(); 

    /** 
     * @param list Parallel relation data collection 
     * @param predicate Judge the root node 
     * @param r The value compared with parentId to determine whether it is the root node 
     * @param <R> The type of the value compared with parentId 
     */ 
    public <R> TreeBuilder (List<T> list, TreePredicate<T,R> predicate, R r){ 
        for(T t: list){ 
            treeNodesMap.put(t.id(), t); 
        } 
        treeNodesMap.values().forEach(v ->{ 
            if(!predicate.test(v,r)){ 
                T p = treeNodesMap.get(v.parentId()); 
                if(p != null){ 
                    p.addChild(v); 
                } 
            }else { 
                rootNodesList.add(v); 
            } 
        }); 
    } 

    public <R> TreeBuilder(List<T> list, R r){ 
        this(list ,TreePredicate.rootNodePredicate(),r); 
    } 

    protected T getTreeNode(Object id) { 
        return treeNodesMap.get(id); 
    } 

    public List<T> getRoot() { 
        return rootNodesList; 
    } 

    public String treeJsonData(){ 
        return JSONObject. toJSONString(rootNodesList); 
    } 

    /**Get all descendants of a node 
     * @param id current node id
     * @return List<TreeNode>
     */
    public List<T> getAllChildren(Object id) {
        List<T> allChildren = new ArrayList<>(16);
        T treeNode = getTreeNode(id);
        for (T t : treeNode.children()) {
            allChildren.add(t);
            allChildren.addAll(getAllChildren(t.id()));
        }
        return allChildren;
    }

    /**获取某一节点所有祖父节点
     */
    public List<T> getAllParent(Object id) {
        List<T> allParent = new ArrayList<>(16);
        T treeNode = getTreeNode(id);
        T parent = treeNodesMap.get(treeNode.parentId());
        if(parent != null){
            allParent.add(parent);
            allParent.addAll(getAllParent((parent.id())));
        }
        return allParent;
    }
}

 

Simple test class, the root node is judged to be an empty string

@Data
public class OrgDTO implements ITreeNode<OrgDTO> {

   @JSONField(ordinal=1)
   private String id;

   @JSONField(ordinal=2)
   private String name;

   @JSONField(ordinal=3)
   private String parentId;


   @JSONField(ordinal=4)
   private List<OrgDTO> children = new ArrayList<>();

   @Override
   public Object id() {
      return getId();
   }

   @Override
   public Object parentId() {
      return getParentId();
   }

   @Override
   public void addChild(OrgDTO orgDTO) {
      children.add(orgDTO);
   }

   @Override
   public List<OrgDTO> children() {
      return children;
   }

   @Override
   public void removeChild(OrgDTO orgDTO) {
      children.remove(orgDTO);
   }


   public OrgDTO(String id, String parentId, String name){
      this.id = id;
      this.parentId = parentId;
      this.name = name;
   }
   public static void main(String[] args) {
      List<OrgDTO> list = new ArrayList<>();
      list.add(new OrgDTO("1","","1"));
      list.add(new OrgDTO("2","1","2"));
      list.add(new OrgDTO("3","2","3"));
      list.add(new OrgDTO("4","3","4"));
      list.add(new OrgDTO("5","4","5"));
      TreeBuilder<OrgDTO> tree = new TreeBuilder<>(list,"");
      System.out.println(tree.treeJsonData());
   }
}

Guess you like

Origin blog.csdn.net/sinat_33472737/article/details/103664181
Recommended