传入一个对象及指定字段
循环
import java.util.ArrayList;
import java.util.List;
public class TreeUtils {
/**
* 将 List 集合转为树状结构
* @param nodes 待转换的 List 集合,其中对象必须包含指定的父级字段和节点ID字段
* @param parentIdField 父级字段名称
* @param idField 节点ID字段名称
* @param <T> 对象类型
* @return 转换后的树状结构
*/
public static <T> List<T> listToTree(List<T> nodes, String parentIdField, String idField) throws NoSuchFieldException, IllegalAccessException {
List<T> treeNodes = new ArrayList<>();
for (T node : nodes) {
Object parentIdValue = getFieldValue(node, parentIdField);
int parentId = Integer.parseInt(parentIdValue.toString());
if (parentId == 0) {
//父ID为0为根节点, 直接加入列表中
treeNodes.add(node);
continue;
}
// 将节点加入对应的父节点中
for (T parent : nodes) {
Object idValue = getFieldValue(parent, idField);
int id = Integer.parseInt(idValue.toString());
if (id == parentId) {
Object children = getFieldValue(parent, "children");
if (children == null){
setFieldValue(parent,"children",new ArrayList());
}
((List<T>)getFieldValue(parent, "children")).add(node);
}
}
}
return treeNodes;
}
/**
* 反射获取对象的属性值
* @param obj 目标对象
* @param fieldName 属性名
* @return 属性值
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static Object getFieldValue(Object obj, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Class<?> clazz = obj.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
}
/**
* 反射设置对象的属性值
* @param obj 目标对象
* @param fieldName 属性名
* @param value 属性值
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void setFieldValue(Object obj, String fieldName, Object value) {
try {
Class<?> clazz = obj.getClass();
java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
使用时调用listToTree方法,并传入待转换的List集合,父级字段名称、节点ID字段名称。示例代码如下:
public class ExampleNode {
private int parentId;
private int id;
private String name;
private List<ExampleNode> children = new ArrayList<>();
// 其他属性和方法
}
List<ExampleNode> nodes = new ArrayList<>();
// 填充节点数据
List<ExampleNode> tree = TreeUtils.listToTree(nodes, "parentId", "id");
递归实现
import java.util.ArrayList;
import java.util.List;
public class TreeUtils {
public static <T> List<T> listToTree(List<T> nodes, String parentIdField, String idField) {
List<T> treeNodes = new ArrayList<>();
for (T node : nodes) {
Object parentIdValue = getFieldValue(node, parentIdField);
int parentId = Integer.parseInt(parentIdValue.toString());
if (parentId == 0) {
// 父ID为0为根节点,直接加入列表中
treeNodes.add(node);
// 递归处理子节点
setChildren(node, nodes, parentIdField, idField);
}
}
return treeNodes;
}
private static <T> void setChildren(T parent, List<T> nodes, String parentIdField, String idField) {
List<T> children = new ArrayList<>();
for (T node : nodes) {
Object parentIdValue = getFieldValue(node, parentIdField);
int parentId = Integer.parseInt(parentIdValue.toString());
Object idValue = getFieldValue(parent, idField);
int id = Integer.parseInt(idValue.toString());
if (parentId == id) {
// 将节点加入对应的父节点中
children.add(node);
// 递归处理子节点
setChildren(node, nodes, parentIdField, idField);
}
}
if (!children.isEmpty()) {
setFieldValue(parent, "children", children);
}
}
/**
* 反射获取对象的属性值
* @param obj 目标对象
* @param fieldName 属性名
* @return 属性值
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static Object getFieldValue(Object obj, String fieldName) {
try {
Class<?> clazz = obj.getClass();
java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(obj);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 反射设置对象的属性值
* @param obj 目标对象
* @param fieldName 属性名
* @param value 属性值
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private static void setFieldValue(Object obj, String fieldName, Object value) {
try {
Class<?> clazz = obj.getClass();
java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
}
}
传入的对象是List<Map<String,Object>>结构
递归
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TreeUtils {
public static List<Map<String, Object>> listToTree(List<Map<String, Object>> nodes, String parentIdField, String idField) {
List<Map<String, Object>> treeNodes = new ArrayList<>();
for (Map<String, Object> node : nodes) {
Object parentIdValue = node.get(parentIdField);
int parentId = Integer.parseInt(parentIdValue.toString());
if (parentId == 0) {
// 父ID为0为根节点,直接加入列表中
treeNodes.add(node);
// 递归处理子节点
setChildren(node, nodes, parentIdField, idField);
}
}
return treeNodes;
}
private static void setChildren(Map<String, Object> parent, List<Map<String, Object>> nodes, String parentIdField, String idField) {
List<Map<String, Object>> children = new ArrayList<>();
for (Map<String, Object> node : nodes) {
Object parentIdValue = node.get(parentIdField);
int parentId = Integer.parseInt(parentIdValue.toString());
Object idValue = parent.get(idField);
int id = Integer.parseInt(idValue.toString());
if (parentId == id) {
// 将节点加入对应的父节点中
children.add(node);
// 递归处理子节点
setChildren(node, nodes, parentIdField, idField);
}
}
if (!children.isEmpty()) {
parent.put("children", children);
}
}
}
List<Map<String, Object>> nodes = new ArrayList<>();
// 填充节点数据
List<Map<String, Object>> treeNodes = TreeUtils.listToTree(nodes, "parentId", "id");
循环
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TreeUtils {
public static List<Map<String, Object>> listToTree(List<Map<String, Object>> nodes, String parentIdField, String idField) {
List<Map<String, Object>> treeNodes = new ArrayList<>();
for (Map<String, Object> node : nodes) {
if (node.get(parentIdField).toString().equals("0")) {
// 父ID为0为根节点,直接加入列表中
treeNodes.add(node);
}
for (Map<String, Object> parentNode : nodes) {
if (parentNode.get(idField).equals(node.get(parentIdField))) {
List<Map<String, Object>> children = (List<Map<String, Object>>) parentNode.get("children");
if (children == null) {
children = new ArrayList<>();
parentNode.put("children", children);
}
children.add(node);
break;
}
}
}
return treeNodes;
}
}
List<Map<String, Object>> nodes = new ArrayList<>();
// 填充节点数据
List<Map<String, Object>> treeNodes = TreeUtils.listToTree(nodes, "parentId", "id");
循环
public class TreeUtils {
/**
* 将 List 转为树形结构
*
* @param list List 数据
* @param idFieldName ID 字段名
* @param parentIdFieldName 父 ID 字段名
* @return 返回树形结构数据
*/
public static List<Map<String, Object>> listToTree(List<Map<String, Object>> list, String idFieldName, String parentIdFieldName) {
List<Map<String, Object>> treeList = new ArrayList<>();
// 将 list 转换为以 id 为 key 的 map
Map<Object, Map<String, Object>> map = new HashMap<>();
for (Map<String, Object> mapItem : list) {
Object id = mapItem.get(idFieldName);
map.put(id, mapItem);
}
for (Map<String, Object> mapItem : list) {
Object parentId = mapItem.get(parentIdFieldName);
if (parentId == null) {
treeList.add(mapItem);
} else {
Map<String, Object> parent = map.get(parentId);
if (parent != null) {
List<Map<String, Object>> children = (List<Map<String, Object>>) parent.get("children");
if (children == null) {
children = new ArrayList<>();
parent.put("children", children);
}
children.add(mapItem);
}
}
}
return treeList;
}
}
使用时,可以按照以下方式调用:
List<Map<String, Object>> list = new ArrayList<>();
// 添加 List 数据
List<Map<String, Object>> treeList = TreeUtils.listToTree(list, "id", "parentId");
// 将 List 转为树形结构数据
其中,list 参数为需要转换的 List 对象,idFieldName 参数为 id 字段名,parentIdFieldName 参数为父 id 字段名,可以根据实际业务场景进行具体实现。
值得注意的是,在工具类中,需要将待转换的 List 对象中的数据转换为以 id 为 key 的 Map,以便在后续的处理中能够快速查找对应节点的父节点,并设置其子节点。同时,在转换过程中,需要在 Map 中保存每个节点的子节点列表信息。
测试
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class TreeInfoDTO implements Serializable {
private static final long serialVersionUID = 6609328309422561896L;
private String id;
private String parentId;
private String name;
private List<TreeInfoDTO> children;
}
public class TestTreeUtils {
public static void main(String[] args) {
TreeInfoDTO treeInfoDTO = new TreeInfoDTO();
treeInfoDTO.setId("0").setName("根");
ArrayList<TreeInfoDTO> treeInfoDTOS = new ArrayList<>();
TreeInfoDTO root = new TreeInfoDTO();
root.setId("1");
root.setParentId("0");
root.setName("Root Node");
List<TreeInfoDTO> levelOneNodes = new ArrayList<>();
TreeInfoDTO node1 = new TreeInfoDTO();
node1.setId("2");
node1.setParentId("1");
node1.setName("Node 1");
TreeInfoDTO node2 = new TreeInfoDTO();
node2.setId("3");
node2.setParentId("1");
node2.setName("Node 2");
levelOneNodes.add(node1);
levelOneNodes.add(node2);
// root.setChildren(levelOneNodes);
List<TreeInfoDTO> levelTwoNodes = new ArrayList<>();
TreeInfoDTO node3 = new TreeInfoDTO();
node3.setId("4");
node3.setParentId("2");
node3.setName("Node 1.1");
TreeInfoDTO node4 = new TreeInfoDTO();
node4.setId("5");
node4.setParentId("2");
node4.setName("Node 1.2");
TreeInfoDTO node5 = new TreeInfoDTO();
node5.setId("6");
node5.setParentId("3");
node5.setName("Node 2.1");
levelTwoNodes.add(node3);
levelTwoNodes.add(node4);
levelTwoNodes.add(node5);
// node1.setChildren(levelTwoNodes);
TreeInfoDTO node6 = new TreeInfoDTO();
node6.setId("7");
node6.setParentId("3");
node6.setName("Node 2.2");
List<TreeInfoDTO> levelThreeNodes = new ArrayList<>();
TreeInfoDTO node7 = new TreeInfoDTO();
node7.setId("8");
node7.setParentId("4");
node7.setName("Node 1.1.1");
TreeInfoDTO node8 = new TreeInfoDTO();
node8.setId("9");
node8.setParentId("5");
node8.setName("Node 1.2.1");
levelThreeNodes.add(node7);
levelThreeNodes.add(node8);
// node3.setChildren(levelThreeNodes);
// node2.setChildren(Arrays.asList(node6));
List<TreeInfoDTO> treeNodes = new ArrayList<>();
treeNodes.add(root);
treeNodes.add(node1);
treeNodes.add(node2);
treeNodes.add(node3);
treeNodes.add(node4);
treeNodes.add(node5);
treeNodes.add(node6);
treeNodes.add(node7);
treeNodes.add(node8);
List<Map<String,Object>> list = JSONObject.parseObject(JSONObject.toJSONString(treeNodes, SerializerFeature.WriteMapNullValue), List.class);
List<Map<String, Object>> maps = TreeUtils.listToTree(list, "parentId", "id");
List<TreeInfoDTO> treeInfoDTOS1 = JSONObject.parseArray(JSONObject.toJSONString(maps, SerializerFeature.WriteMapNullValue), TreeInfoDTO.class);
treeInfoDTO.setChildren(treeInfoDTOS1);
System.out.println(JSONObject.toJSONString(treeInfoDTO));
}
}