Java 从平面列表构建层次列表

Java 从平面列表构建层次列表,java,Java,我有一个列表,其中包含由相同类型(类)表示的所有父级和子级。我想从平面列表生成层次列表 下面是我代表父母和孩子的班级。在这里,我需要基于parentId映射父对象的子对象。根级别(无父级)以parentId0开始 import java.util.ArrayList; import java.util.List; class Customers { private int id; private String name; private int parentId;

我有一个列表,其中包含由相同类型(类)表示的所有父级和子级。我想从平面列表生成层次列表

下面是我代表父母和孩子的班级。在这里,我需要基于parentId映射父对象的子对象。根级别(无父级)以parentId0开始

import java.util.ArrayList;
import java.util.List;

class Customers {

    private int id;
    private String name;
    private int parentId;
    private List<Customers> childs;

    public Customers(int id, String name, int parentId) {
        this(id, name, parentId, null);
    }

    public Customers(int id, String name, int parentId, List<Customers> childs) {
        this.id = id;
        this.name = name;
        this.parentId = parentId;
        this.childs = childs;
    }

}

public class Application {

    public static void main(String[] args) {
        //Input List
        Customers customer = new Customers(1, "Hel", 0);
        Customers customerChild1 = new Customers(2, "Hel-Child1", 1);
        Customers customerChild2 = new Customers(5, "Hel-Child2", 1);
        Customers customerInnerChild1 = new Customers(3, "Hel-InnerChild1", 2);
        Customers customerInnerChild2 = new Customers(4, "Hel-InnerChild2", 2);

        List<Customers> customers = new ArrayList();
        customers.add(customerInnerChild1);
        customers.add(customerInnerChild2);
        customers.add(customer);
        customers.add(customerChild1);
        customers.add(customerChild2);
    }

    public static List<Customers> hierarchicalList(List<Customers> Customers) {
        return null;
    }
}
预期输出:

[
  {
    "id": 1,
    "name": "Hel",
    "parentId": 0,
    "childs": [
      {
        "id": 2,
        "name": "Hel-Child1",
        "parentId": 1,
        "childs": [
          {
            "id": 3,
            "name": "Hel-InnerChild1",
            "parentId": 2
          }, {
            "id": 4,
            "name": "Hel-InnerChild2",
            "parentId": 2
          }
        ]
      }, {
        "id": 5,
        "name": "Hel-Child2",
        "parentId": 1
      }
    ]
  }
]

注意:输入列表未排序。

该类已具有层次结构

如果您打印父对象,然后递归打印子对象,您将看到一棵树

你预计会发生什么

这只是一个如何在树上迭代的问题:深度优先还是广度优先

关于从平面列表到树的问题是关于解析平面列表。你如何区分单子上的父母和孩子?这应该给你一个如何继续的提示


您需要一个factory类,该类获取客户列表,解析列表,并在适当的树结构中返回客户及其子级的根实例。

如果您只需要检查每个子级的父级,您只需要筛选列表并为每个元素设置子级。大概是这样的:

public List<Customer> getHierarchicalList(final List<Customer> originalList) {
    final List<Customer> copyList = new ArrayList<>(originalList);

    copyList.forEach(element -> {
        originalList
                .stream()
                .filter(parent -> parent.id == element.parentId)
                .findAny()
                .ifPresent(parent -> {
                    if (parent.childs == null) {
                        parent.childs = new ArrayList<>();
                    }
                    parent.childs.add(element);
                    originalList.remove(element);
                });
    });
    return originalList;
}
公共列表GetHierarchyCallist(最终列表原始列表){
最终列表copyList=新数组列表(originalList);
copyList.forEach(元素->{
原创作家
.stream()
.filter(parent->parent.id==element.parentId)
.findAny()
.ifPresent(父级->{
if(parent.childs==null){
parent.childs=新的ArrayList();
}
parent.childs.add(元素);
原始列表。删除(元素);
});
});
回归原创者;
}

我想扩展Rhuan的答案

通过使用Rhuan的代码,您将获得根级别上的所有节点,并且只有一个节点具有正确的内容和顺序,通过删除错误的内容,您将获得更好的结果:

public List<Customer> getHierarchicalList(final List<Customer> originalList) {
    final List<Customer> copyList = new ArrayList<>(originalList);

    copyList.forEach(element -> {
        originalList
                .stream()
                .filter(parent -> parent.id == element.parentId)
                .findAny()
                .ifPresent(parent -> {
                    if (parent.childs == null) {
                        parent.childs = new ArrayList<>();
                    }
                    parent.childs.add(element);
                    /* originalList.remove(element); don't remove the content before completing the recursive */
                });
    });
    originalList.subList(1, originalList.size()).clear();
    return originalList;
}
公共列表GetHierarchyCallist(最终列表原始列表){
最终列表copyList=新数组列表(originalList);
copyList.forEach(元素->{
原创作家
.stream()
.filter(parent->parent.id==element.parentId)
.findAny()
.ifPresent(父级->{
if(parent.childs==null){
parent.childs=新的ArrayList();
}
parent.childs.add(元素);
/*删除(元素);在完成递归之前不要删除内容*/
});
});
originalList.subList(1,originalList.size()).clear();
回归原创者;
}

关于子列表的注释已清除。

我还想扩展Rhuan答案

如果他的代码导致无限循环,则需要比较父元素id和元素id,它们不应相等
parent.id!=element.id

因此,您的代码将是:

public List<Customer> getHierarchicalList(final List<Customer> originalList) {
    final List<Customer> copyList = new ArrayList<>(originalList);

    copyList.forEach(element -> {
        originalList
                .stream()
                .filter(parent -> parent.id == element.parentId && parent.id != element.id)
                .findAny()
                .ifPresent(parent -> {
                    if (parent.childs == null) {
                        parent.childs = new ArrayList<>();
                    }
                    parent.childs.add(element);
                    originalList.remove(element);
                });
    });
    return originalList;
}
公共列表GetHierarchyCallist(最终列表原始列表){
最终列表copyList=新数组列表(originalList);
copyList.forEach(元素->{
原创作家
.stream()
.filter(parent->parent.id==element.parentId&&parent.id!=element.id)
.findAny()
.ifPresent(父级->{
if(parent.childs==null){
parent.childs=新的ArrayList();
}
parent.childs.add(元素);
原始列表。删除(元素);
});
});
回归原创者;
}

“该方法应返回包含父关系和子关系的列表。”我不明白你的意思。一份综合清单?到目前为止你试过什么?也许这会让我们了解一下你所说的“等级列表”是什么意思。@daniu,更新了我的问题。我什么也没做。@hellzone,更新了我的问题,请检查。我只是不知道你怎么知道Hell-InnerChild1和Hell-InnerChild2是Hell-Child1的孩子,而不是Hell-Child2?它将是无限循环,你能用我的输入试试吗。我这里没有无限循环运行你的输入。。。但在将子项添加到空的子项列表时存在NPE。。。我已经更改了方法以避免NPE,但我鼓励您在构造函数中初始化子数组,这样它就永远不会为空。我得到的异常:线程“main”java.lang.StackOverflower中的异常位于java.lang.StringBuilder.append(StringBuilder.java:136)com.collections.Customers.toString(Application.java:58)java.lang.String.valueOf(String.java:2994)java.lang.StringBuilder.append(StringBuilder.java:131)java.util.AbstractCollection.toString(AbstractCollection.java:462)java.lang.String.valueOf(String.java:2994)java.lang.StringBuilder.append(StringBuilder.java:131)com.collections.Customers.toString(Application.java:58)在java.lang.String.valueOf(String.java:2994)好的,现在运行我的代码,我得到了与您在问题中建议的相同的输出。但即使是现在,我也无法得到这个无限循环人。我正在使用IntelliJ IDEA作为我的IDE。。。如果你需要更多的帮助,你可以私下和我谈谈,我很乐意帮助你:rhuankarlus@gmail.comwhen我尝试了这段代码,我只得到了2级递归..没有进入3级,而是用实际输入和预期输出更新了我的问题。你能检查一下吗?应该很简单。浏览列表并检查每个条目。如果它有父id,请将其添加到父列表中。应该只有一个客户没有父客户。这是树的根。这里我有n个根级别的父级和n个子级。因此,我正在寻找有效的解决方案。我可以迭代100000个项目。我被教导一棵树只有一个根。如果你有多个根,你就有多棵树,不是吗
public List<Customer> getHierarchicalList(final List<Customer> originalList) {
    final List<Customer> copyList = new ArrayList<>(originalList);

    copyList.forEach(element -> {
        originalList
                .stream()
                .filter(parent -> parent.id == element.parentId && parent.id != element.id)
                .findAny()
                .ifPresent(parent -> {
                    if (parent.childs == null) {
                        parent.childs = new ArrayList<>();
                    }
                    parent.childs.add(element);
                    originalList.remove(element);
                });
    });
    return originalList;
}