开发用工具类2.0:无侵入式的树形状工具类TreeUtils

package cn.jow.util;


import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* 无侵入方式处理对象集合,树形状结构数据,无递归
* <pre>
* 功能:
* 1:对象集合或者Map集合==>包含指定属性的指定值
*
* 2:对象集合或者Map集合==>Map<key,obj>
* 3:对象集合或者Map集合==>Map<key,value>
* 4:对象集合或者Map集合==>Map<key,List<obj>>
* 5:对象集合或者Map集合==>Map<key,List<value>>
*
* 6:对象集合或者Map集合==>查找上层的全部节点或者指定层级节点
* 7:对象集合或者Map集合==>查找上层的全部节点id或者指定层级节点id
* 8:对象集合或者Map集合==>查找子层的全部节点或者指定层级节点
* 9:对象集合或者Map集合==>查找子层的全部节点id或者指定层级节点id
*
* 10:对象集合或者Map集合<==>树形状结构
* 特点:
* 1.不会重新重新创建业务对象
* 2.不改变对象排序,若要排序,请先排序好再使用
* 3.仅仅需要jdk8就可以运行,不需要引入其他包
* 4.自测通过,效率不差。
* 5.都是基于java.util的特定处理代码,加入了一点点steam流的使用
* 6.以下方法都没用递归,请自行了解最大递归深度
* 疑问:
* 1.总数不对可能因为环形结构的节点被抛弃
* 2.总数不对可能因为有父节点id但父节点不存在的节点会被抛弃
* 3.完全不支持多线程处理同一个源数据集合
* 说明:
* 所见即所得,希望你觉得好用。良心若不痛,删掉作者信息,占为己用都不碍事。
* </pre>
*
* @author JunOneWolf
* @version 2.0
* @date 2023-02-01
*/

public class TreeUtils {
private TreeUtils() {
}
//--------------------------------------是否包含某个属性的值------------------------------------------------------------------

/**
* 根据对象某个属性筛选部分对象
*
* @param srcList 源对象
* @param equalsValue 比较字符串
* @param attribute 取值字段
* @param <T> 泛型
* @return 包含指定属性的指定值
*/
public static <T> boolean containsAttribute(String equalsValue, List<T> srcList, Function<T, ? extends String> attribute) {
return Objects.nonNull(equalsValue) && Objects.nonNull(attribute)
&& Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.anyMatch(s -> Objects.nonNull(s) && equalsValue.equals(attribute.apply(s)));
}

/**
* 根据对象某个属性筛选部分对象
*
* @param srcList 源对象
* @param equalsValue 比较字符串
* @param attribute 取值字段
* @return 包含指定属性的指定值
*/
public static boolean containsAttribute(String equalsValue, List<Map<String, Object>> srcList, String attribute) {
return Objects.nonNull(equalsValue) && Objects.nonNull(attribute)
&& Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.anyMatch(s -> Objects.nonNull(s) && equalsValue.equals(s.get(attribute)));
}

//--------------------------------------筛选出对象属性存入到map中------------------------------------------------------------------

/**
* @param srcList 对象集合
* @param keyField 字段的值作为key
* @param <T> 泛型
* @return Map<key, obj>
*/
public static <T> Map<String, T> entityList2Map(List<T> srcList, Function<T, ? extends String> keyField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && Objects.nonNull(keyField.apply(s)))
.collect(Collectors.toMap(keyField, v -> v, (a, b) -> a));
}

/**
* @param srcList 对象集合
* @param keyField 字段的值作为key
* @param valueField 字段的值作为value
* @param <T> 泛型
* @return Map<key, value>
*/
public static <T> Map<String, ?> entityList2Map(List<T> srcList, Function<T, ? extends String> keyField, Function<T, ?> valueField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && keyField.apply(s) != null && valueField.apply(s) != null)
.collect(Collectors.toMap(keyField, valueField));
}


/**
* @param srcList 对象集合
* @param keyField 字段的值作为key
* @param <T> 泛型
* @return Map<key, List < obj>>
*/
public static <T> Map<String, List<T>> entityList2Maps(List<T> srcList, Function<T, ? extends String> keyField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && keyField.apply(s) != null)
.collect(Collectors.groupingBy(keyField));
}

/**
* @param srcList 对象集合
* @param keyField 字段的值作为key
* @param valueField 字段的值作为value
* @param <T> 泛型
* @return Map<key, List < value>>
*/
public static <T> Map<String, List<String>> entityList2Maps(List<T> srcList, Function<T, ? extends String> keyField, Function<T, ? extends String> valueField) {
return Objects.isNull(srcList) ? new HashMap<>() : srcList.stream()
.filter(s -> Objects.nonNull(s) && Objects.nonNull(keyField.apply(s)) && Objects.nonNull(valueField.apply(s)))
.collect(Collectors.groupingBy(keyField, Collectors.mapping(valueField, Collectors.toList())));
}


/**
* @param srcList 源对象集合
* @param keyField 字段的值作为key
* @return Map<key, obj>
*/
public static Map<String, Map<String, Object>> mapList2Map(List<Map<String, Object>> srcList, String keyField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && Objects.nonNull(s.get(keyField)))
.collect(Collectors.groupingBy(s -> s.get(keyField).toString(),
Collectors.collectingAndThen(Collectors.toList(), v -> v.get(0))));
}

/**
* @param srcList 源对象集合
* @param keyField 字段的值作为key
* @param valueField 字段的值作为value
* @return Map<key, value>
*/
public static Map<String, Object> mapList2Map(List<Map<String, Object>> srcList, String keyField, String valueField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && Objects.nonNull(s.get(keyField)))
.collect(Collectors.groupingBy(s -> s.get(keyField).toString(),
Collectors.collectingAndThen(Collectors.toList(), v -> v.get(0).get(valueField))));
}

/**
* @param srcList 源对象集合
* @param keyField 字段的值作为key
* @return Map<key, List < obj>>
*/
public static Map<String, List<Map<String, Object>>> mapList2Maps(List<Map<String, Object>> srcList, String keyField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && Objects.nonNull(s.get(keyField)))
.collect(Collectors.groupingBy(s -> s.get(keyField).toString(), Collectors.toList()));
}

/**
* @param srcList 源对象集合
* @param keyField 字段的值作为key
* @param valueField 字段的值作为value
* @return Map<key, List < value>>
*/
public static Map<String, List<Object>> mapList2Maps(List<Map<String, Object>> srcList, String keyField, String valueField) {
return Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream()
.filter(s -> Objects.nonNull(s) && Objects.nonNull(s.get(keyField)))
.collect(Collectors.groupingBy(s -> s.get(keyField).toString()
, Collectors.collectingAndThen(Collectors.toList()
, s -> s.stream().map(b -> b.get(valueField)).collect(Collectors.toList()))));

}

//----------------------------------查找上层集合------------------------------------------------------------------

/**
* @param srcArray 单列表节点
* @param equalsId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param <T> 泛型
* @return 上层对象节点集合(父, 爷顺序往上)
*/
public static <T> List<T> findAllParentOfEntity(String equalsId, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField) {
return findParentOfEntity(equalsId, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param equalsId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param level 层级
* @param <T> 泛型
* @return 上层对象节点集合(父, 爷顺序往上)
*/
public static <T> List<T> findParentOfEntity(String equalsId, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField, int level) {
List<T> result = new LinkedList<>();
checkParam(childField, parentField);
if (srcArray != null && srcArray.size() > 0) {
Map<String, ?> map = entityList2Map(srcArray, childField, parentField);
List<String> useIdList = findParentIdListByMap(map, equalsId, level);
Map<String, List<T>> idAndListMap = entityList2Maps(srcArray, childField);
useIdList.forEach(s -> result.addAll(Optional.ofNullable(idAndListMap.get(s)).orElse(new ArrayList<>())));
}
return new ArrayList<>(result);
}

/**
* @param srcArray 单列表节点
* @param childId 子节点id
* @param childField 查找的字段
* @param parentField 父节点字段
* @return 上层对象节点集合(父, 爷顺序往上)
*/
public static <T1, T2> List<Map<T1, T2>> findAllParentOfMap(Object childId, List srcArray, String childField, String parentField) {
return findParentOfMap(childId, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param childId 子节点id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param level 层数
* @return 上层节点id集合(父, 爷顺序往上)
*/
public static <T1, T2> List<Map<T1, T2>> findParentOfMap(Object childId, List srcArray, String childField, String parentField, int level) {
List<Map<T1, T2>> result = new ArrayList<>();
checkParam(childField, parentField);
if (srcArray != null && srcArray.size() > 0 && childId != null) {
List<String> userIdList = findParentIdListByMap(mapList2Map(srcArray, childField, parentField), childId.toString(), level);
Map<String, List> idAndListMap = mapList2Maps(srcArray, childField);
userIdList.forEach(s -> result.addAll(Optional.ofNullable(idAndListMap.get(s)).orElse(new ArrayList<>())));
}
return result;
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @return 上层节点id集合(父, 爷顺序往上)
*/
public static List<String> findAllParentIdOfMap(Object childId, List srcArray, String childField, String parentField) {
return findParentIdOfMap(childId, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @return 上层节点id集合(父, 爷顺序往上)
*/
public static List<String> findParentIdOfMap(Object childId, List srcArray, String childField, String parentField, int level) {
checkParam(childField, parentField);
if (srcArray != null && srcArray.size() > 0 && childId != null) {
return findParentIdListByMap(mapList2Map(srcArray, childField, parentField), childId.toString(), level);
}
return new ArrayList<>();
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param <T> 泛型
* @return 上层节点id集合(父, 爷顺序往上)
*/
public static <T> List<String> findAllParentIdOfEntity(String childId, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField) {
return findParentIdListByMap(entityList2Map(srcArray, childField, parentField), childId, -1);
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param <T> 泛型
* @return 上层对象节点集合(父, 爷顺序往上)
*/
public static <T> List<String> findParentIdOfEntity(String childId, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField, int level) {
return findParentIdListByMap(entityList2Map(srcArray, childField, parentField), childId, level);
}

/**
* 从map取出上级,一层一层,尽头或者重复就会则停止
*
* @param idAndParentIdMap 层级节点结构
* @param id 对比的节点
* @return 上层的id
*/
private static List<String> findParentIdListByMap(Map idAndParentIdMap, String id, int level) {
List<String> result = new ArrayList<>();
Map<String, String> tempIdAndParentIdMap = (Map<String, String>) idAndParentIdMap;
Set<String> useIdSet = new HashSet<>();
//过滤当前节点
while (tempIdAndParentIdMap.containsKey(id) && !useIdSet.contains(id)) {
if (level > 0) {
level--;
} else if (level == 0) {
break;
}
useIdSet.add(id);
String tempId = tempIdAndParentIdMap.get(id);
result.add(tempId);
if (tempIdAndParentIdMap.containsKey(tempId)) {
id = tempId;
} else {
break;
}
}
return result;
}

//------------------------------------查找子节点---------------------------------------------------------------------------

/**
* @param srcArray 单列表节点
* @param id 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param <T> 泛型
* @return 子节点对象集合
*/
public static <T> List<T> findAllChildOfEntity(String id, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField) {
return findChildOfEntity(id, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param id 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param level 层级
* @param <T> 泛型
* @return 子节点对象集合
*/
public static <T> List<T> findChildOfEntity(String id, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField, int level) {
List<T> result = new LinkedList<>();
checkParam(childField, parentField);
if (srcArray != null && srcArray.size() > 0) {
Map<String, List<T>> srcMap = entityList2Maps(srcArray, childField);
List<String> childIdList = findChildIdListByMap(entityList2Maps(srcArray, parentField, childField), Collections.singletonList(id), level);
childIdList.forEach(s -> result.addAll(srcMap.get(s)));
}
return result;
}

/**
* @param id 子节点id
* @param srcArray 单列表节点
* @param childField 查找的字段
* @param parentField 父节点字段
* @return 子节点对象集合
*/
public static <T1, T2> List<Map<T1, T2>> findAllChildOfMap(Object id, List srcArray, String childField, String parentField) {
return findChildOfMap(id, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param id 子节点id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param level 层级
* @return 子节点对象集合
*/
public static <T1, T2> List<Map<T1, T2>> findChildOfMap(Object id, List srcArray, String childField, String parentField, int level) {
List<Map<T1, T2>> result = new ArrayList<>();
checkParam(childField, parentField);
if (srcArray != null && srcArray.size() > 0 && id != null) {
List<String> userIdList = findChildIdListByMap(mapList2Map(srcArray, childField, parentField), Collections.singletonList(id.toString()), level);
Map<String, List> idAndListMap = mapList2Maps(srcArray, childField);
userIdList.forEach(s -> result.addAll(idAndListMap.get(s)));
}
return result;
}

/**
* @param srcArray 单列表节点
* @param id 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @return 子节点id集合
*/
public static List<String> findAllChildIdOfMap(Object id, List srcArray, String childField, String parentField) {
return findChildIdOfMap(id, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param level 层级
* @return 子节点id集合
*/
public static List<String> findChildIdOfMap(Object childId, List srcArray, String childField, String parentField, int level) {
checkParam(childField, parentField);
if (childId == null || childId.toString().length() == 0) {
return new ArrayList<>();
}
return findChildIdListByMap(mapList2Maps(srcArray, parentField, childField), Collections.singletonList(childId.toString()), level);
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param <T> 泛型
* @return 子节点id集合
*/
public static <T> List<String> findAllChildIdOfEntity(String childId, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField) {
return findChildIdOfEntity(childId, srcArray, childField, parentField, -1);
}

/**
* @param srcArray 单列表节点
* @param childId 目标查找id
* @param childField 查找的字段
* @param parentField 父节点字段
* @param level 层级
* @param <T> 泛型
* @return 子节点id集合
*/
public static <T> List<String> findChildIdOfEntity(String childId, List<T> srcArray, Function<T, ? extends String> childField, Function<T, ? extends String> parentField, int level) {
checkParam(childField, parentField);
return findChildIdListByMap(entityList2Maps(srcArray, parentField, childField), Collections.singletonList(childId), level);
}


/**
* 查找子节点,过滤已经使用过的id。
*
* @param parentAndChildMap 层级节点结构
* @param idList 选择的子节点数量
*/
private static List<String> findChildIdListByMap(Map<String, List<String>> parentAndChildMap, List<String> idList, int level) {
//防止重复字段
Set<String> useIdSet = new HashSet<>();
List<String> result = new ArrayList<>(parentAndChildMap.size());
List<String> targetList = new LinkedList<>(idList);
//一整层一整层的获取,
while (targetList.size() > 0) {
if (level > 0) {
level--;
} else if (level == 0) {
break;
}
List<String> tempSonIdList = new LinkedList<>();
for (String id : targetList) {
List<String> childIdList = parentAndChildMap.get(id);
if (childIdList != null && childIdList.size() > 0) {
//移除掉已使用的
childIdList.removeAll(useIdSet);
result.addAll(childIdList);
useIdSet.addAll(childIdList);
tempSonIdList.addAll(childIdList);
}
}
targetList = tempSonIdList;
}
return result;
}


//------------------------------------树形状和集合的互转---------------------------------------------------------------------------

/**
* List<Map>生成树形状结构
*
* @param srcList 对象集合
* @param childField 当前节点字段
* @param parentField 上层节点字段
* @param saveField 子节点集合的存储字段
* @return 父节点为null或者为""的第一层集合
*/
public static <T1, T2> List<Map<T1, T2>> mapList2Tree(List srcList, String childField, String parentField, String saveField) {
checkParam(childField, parentField, saveField);
List result = new LinkedList();
Map<String, List<Map<T1, T2>>> linkMap = mapList2Maps(srcList, parentField);
Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream().filter(Objects::nonNull).forEach(s -> {
Map map = (Map) s;
Object parentId = map.get(parentField);
if (parentId == null || parentId.toString().length() == 0) {
result.add(s);
}
Object childId = map.get(childField);
if (childId != null && childId.toString().length() > 0) {
Optional.ofNullable(linkMap.get(childId.toString())).ifPresent(a -> map.put(saveField, a));
}
});
return new ArrayList<>(result);
}

/**
* List<Entity>生成树形状结构
*
* @param srcList 源集合
* @param childField 子字段
* @param parentField 父字段
* @param saveField 子节点集合的存储字段
* @param <T> 泛型
* @return 父节点为null或者为""的第一层集合
*/
public static <T> List<T> entityList2Tree(List<T> srcList, Function<T, ? extends String> childField, Function<T, ? extends String> parentField, Function<T, ? extends List<T>> saveField) {
checkParam(childField, parentField, saveField);
List<T> result = new ArrayList<>();
Map<String, List<T>> linkMap = entityList2Maps(srcList, parentField);
Optional.ofNullable(srcList).orElse(new ArrayList<>()).stream().filter(Objects::nonNull).forEach(s -> {
String parentId = parentField.apply(s);
if (parentId == null || parentId.length() == 0) {
result.add(s);
}
String childId = childField.apply(s);
if (childId != null && childId.length() > 0) {
Optional.ofNullable(linkMap.get(childId)).ifPresent(a -> {
List<T> tempList = saveField.apply(s);
tempList.addAll(a);
}
);
}
});
return result;
}

/**
* 一维的集合,获取符合条件的对象集合。
* &&&温馨提示,每个对象的childField字段的关系依然存在&&&
*
* @param srcList 来源集合
* @param childField 属性字段
* @param <T> 泛型
* @return 一维的集合
*/
public static <T> List<T> tree2EntityList(List<T> srcList, Function<T, ? extends List<T>> childField) {
return tree2EntityList(srcList, childField, -1);
}

/**
* 一维的集合,获取符合条件的对象集合。
* &&&温馨提示,每个对象的childField字段的关系依然存在&&&
*
* @param srcList 来源集合
* @param childField 属性字段
* @param level 层级
* @param <T> 泛型
* @return 一维的集合
*/
public static <T> List<T> tree2EntityList(List<T> srcList, Function<T, ? extends List<T>> childField, int level) {
checkParam(childField);
if (srcList == null || srcList.size() == 0) {
return new ArrayList<>();
}
List<T> result = new LinkedList<>(srcList);
Set<T> useObj = new HashSet<>();
List<T> targetList = new LinkedList<>(srcList);
//一整层一整层的获取,
while (targetList.size() > 0) {
if (level > 0) {
level--;
} else if (level == 0) {
break;
}
List<T> tempSonIdList = new LinkedList<>();
for (T obj : targetList) {
if (obj == null) {
continue;
}
List<T> childIdList = childField.apply(obj);
if (childIdList != null && childIdList.size() > 0) {
//移除掉已使用的
childIdList.removeAll(useObj);
useObj.addAll(childIdList);
result.addAll(childIdList);
tempSonIdList.addAll(childIdList);
}
}
targetList = tempSonIdList;
}
return new ArrayList<>(result);
}

/**
* 树形状转化单一列表
*
* @param srcList 来源对象
* @param childField 子节点对象
* @param <T1> 泛型
* @param <T2> 泛型
* @return 单列表集合
*/
public static <T1, T2> List<Map<T1, T2>> tree2MapList(List srcList, String childField) {
return tree2MapList(srcList, childField, -1);
}

/**
* 树形状转化单一列表
*
* @param srcList 来源对象
* @param childField 子节点对象
* @param level 层级
* @param <T1> 泛型
* @param <T2> 泛型
* @return 单列表集合
*/
public static <T1, T2> List<Map<T1, T2>> tree2MapList(List srcList, String childField, int level) {
checkParam(childField);
if (srcList == null || srcList.size() == 0) {
return new ArrayList<>();
}
List<Map<T1, T2>> result = new LinkedList<>(srcList);
Set<Map<T1, T2>> useObj = new HashSet<>();
List<Map<T1, T2>> targetList = new LinkedList<>(srcList);
//一整层一整层的获取,
while (targetList.size() > 0) {
if (level > 0) {
level--;
} else if (level == 0) {
break;
}
List<Map<T1, T2>> tempSonIdList = new LinkedList<>();
for (Map<T1, T2> obj : targetList) {
if (obj == null) {
continue;
}
List<Map<T1, T2>> childIdList = (List<Map<T1, T2>>) obj.get(childField);
if (childIdList != null && childIdList.size() > 0) {
//移除掉已使用的
childIdList.removeAll(useObj);
useObj.addAll(childIdList);
result.addAll(childIdList);
tempSonIdList.addAll(childIdList);
}
}
targetList = tempSonIdList;
}
return new ArrayList<>(result);
}

/**
* 检测使用的参数是否重复,相等
*/
private static void checkParam(Object... array) {
Set<String> objSet = new HashSet<>();
for (Object param : array) {
if (Objects.isNull(param) || param.toString().length() == 0) {
throw new RuntimeException("编码参数异常");
}
objSet.add(param.toString());
}
//暂时只支持判定字符串
if (objSet.size() != array.length) {
throw new RuntimeException("编码参数异常");
}
}
}
posted @   未名缺爱人  阅读(97)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示