列表转树结构,清除无子节点的节点,获取节点到根的路径
列表转树结构
逻辑上呈树结构的数据,诸如菜单,省市区,在数据库中单表存放,Java程序从数据库中读取出来这些数据时,是列表形式。列表转树结构使用双层for循环实现:
/**
* 节点组成树形结构,返回森林
*
* @param list 节点列表
* @param predicate 定义树的根节点
* @return 森林
*/
static <T extends ITree<T>> List<T> toForest(List<T> list, Predicate<T> predicate) {
for (T item : list) {
List<T> children = list.stream()
.filter(c -> Objects.equals(c.getParentId(), item.getId()))
.collect(Collectors.toList());
item.setChildren(children);
}
List<T> tree = list.stream().filter(predicate)
.collect(Collectors.toList());
return tree;
}
清除空目录
/**
* 清除空的子目录
*/
private void clearEmptyChildren(DaCalGroup group) {
Iterator<DaCalGroup> iterator = group.getChildren().iterator();
while (iterator.hasNext()) {
DaCalGroup child = iterator.next();
if (child.getGroupType() == 1L) continue;
clearEmptyChildren(child);
if (child.getChildren().isEmpty()) {
iterator.remove();
}
}
}
获取节点至根的路径
使用递归的样例代码如下:
/**
* 例如 areaCode=130400时,返回河北省邯郸市
* 例如 areaCode=130000时,返回河北省
*
* @param areaCode 省、市、区级编码
* @return 从省级全名拼接到areaCode全名的路径
*/
public String getPathFullname(String areaCode) {
AreaDict areaDict = dao.findByAreaCode(areaCode).orElse(null);
if (areaDict == null) return "";
if (!COUNTRY_CODE.equals(areaDict.getParentCode())) {
return getPathFullname(areaDict.getParentCode()) + areaDict.getFullname();
}
return areaDict.getFullname();
}
可以优化为使用双层for循环,list保存中间的迭代结果的方式,替代递归。
伪代码:
function(areaCode){
List list = new List();
list.add(areaCode)
while(list.tail is not root){
list.add(parent(list.tail))
}
return list.reverse().join()
}