获取深度对象中的每个对象

时间:2017-12-10 16:12:32

标签: java recursion collections java-8 depth

我有这个Person对象。每个人都有人物对象列表等等,它可以深入无限

    public class Person {

        private List<Person> people = new ArrayList<>();

        public Person() {
        }

        ...

        public List<Person> getPeople() {
            return people;
        }

        public void setPeople(List<Person> people) {
            this.people = people;
        }

        public int maxDepth() {
            int maxChildrenDepth = 0;
            for (Person prs: people) {
                maxChildrenDepth = Math.max(maxChildrenDepth, prs.maxDepth());
            }
            return 1 + maxChildrenDepth;
        }

        public static Set<Person> getPersonLevel(Person person, int depth) {
            Set<Person> ppl= new HashSet<>();
            if (depth > 0) {
                 person.getPeople().forEach(prs -> ppl.addAll(getPersonLevel(prs, depth - 1)));
    }
      return ppl;
    } 

问题1:方法 - &gt; maxDepth不起作用。在该图像中,正确的最大深度为3(请参阅带圆圈的),但该方法给出的值为4。

问题2:根据maxDepth,我希望得到列表中的所有人。例如,如果我通过maxdept 3传递person对象,如果我将深度传递为2,我应该得到所有 person 1 person 2 NOT person 3 < / strong>在该图表的列表中。我通过编写该方法尝试了这项工作 - &gt; public static设置getPersonLevel(Person person,int depth),但这不起作用,因为它一直返回空集。

感谢任何帮助

enter image description here

2 个答案:

答案 0 :(得分:2)

我修改了你的代码如下:

public class Person {
        private List<Person> people = new ArrayList<>();
        private String name;
        public Person() {
        }
        public Person(String name) {
            this.name = name;
        }
        public List<Person> getPeople() {
            return people;
        }
        public void setPeople(List<Person> people) {
            this.people = people;
        }

        public int maxDepth() {
            if (people.isEmpty()) {
                return 0;
            }
            int maxChildrenDepth = 0;
            for (Person prs: people) {
                maxChildrenDepth = Math.max(maxChildrenDepth, prs.maxDepth());
            }
            return 1+maxChildrenDepth;
        }

       public static void getPersonLevel(Person person, int depth, Set<Person> ppl) {
            if (depth <= 0) {
                return;
            } else {
                for (Person prs : person.getPeople()) {
                    getPersonLevel(prs, depth - 1, ppl);
                }
            }
            ppl.addAll(person.getPeople());
       }

      //just for logging
       @Override
       public String toString() {
            return "Person [name=" + name + "]";
      }
}

问题1的客户代码:p0 - &gt;人0

System.out.println(p0.maxDepth());

问题2的客户端代码: p0 - &gt;人0

Set<Person> ppl= new HashSet<>();
int depth = 2;
System.out.println(p0.getPersonLevel(p0, depth, ppl));

希望这会有所帮助。

答案 1 :(得分:2)

在你的方法中

    public int maxDepth() {
        int maxChildrenDepth = 0;
        for (Person prs: people) {
            maxChildrenDepth = Math.max(maxChildrenDepth, prs.maxDepth());
        }
        return 1 + maxChildrenDepth;
    }

显而易见的是,单个Person对象(其列表中没有任何元素)已经返回1(一)的深度。所以每个附加级别都会添加一个,在你的图片中,你有四个级别,所以你得到了四个结果。

你的方法

public static Set<Person> getPersonLevel(Person person, int depth) {
    Set<Person> ppl= new HashSet<>();
    if (depth > 0) {
         person.getPeople().forEach(prs -> ppl.addAll(getPersonLevel(prs, depth - 1)));
    }
    return ppl;
}

遍历整个Person树,遍历所有级别,但在任何时候,它实际上都是向Set添加任何元素。它只是addAll使用这个递归方法的另一个结果,但是只要没有实际添加发生,结果就是一个空集,并且使用带有空集的addAll也不会添加任何元件。

主要障碍是您显然不想包含/计算您正在评估/调用方法的Person实例。我建议直接将此行为设置为可选,因此在遍历树时,您可以指示方法始终计算子元素。然后,您可以提供其他方法,其默认行为是不计算根元素:

public class Person {
    private List<Person> people = new ArrayList<>();

    public Person() {
    }
    public List<Person> getPeople() {
        return people;
    }
    public void setPeople(List<Person> people) {
        this.people = people;
    }

    public Stream<Person> people() {
        return people.stream();
    }

    public Stream<Person> peopleLevel(int depth, boolean includeThis) {
        if(depth<0) throw new IllegalArgumentException();
        if(depth==0) return includeThis? Stream.of(this): Stream.empty();
        Stream<Person> sub = people();
        if(depth > 1) sub = sub.flatMap(p -> p.peopleLevel(depth-1, true));
        return includeThis? Stream.concat(Stream.of(this), sub): sub;
    }

    public static Set<Person> getPersonLevel(Person person, int depth) {
        return person.peopleLevel(depth, false).collect(Collectors.toSet());
    }

    public int maxDepth() {
        return maxDepth(false);
    }
    public int maxDepth(boolean includeThis) {
        int chDepth = people().mapToInt(p -> p.maxDepth(true)).max().orElse(0);
        if(includeThis) chDepth++;
        return chDepth;
    }
}