kwh
kwh

Reputation: 664

Java 8 Nested stream find minimum

I have a data structure like this:

class Parent {
  List<Child> children;
}
class Child {
  DateTime date;
}

List<Parent> parents = ...

I want to find the earliest Child DateTime in all the parents

I want one result. The earliest DateTime across all the parents and all their children.

List<Parent> parents = create();

List<Child> epp = new ArrayList<Child>();//earliest per parent

parents.forEach(c -> c.getChildren()
                      .stream()
                      .min(Comparator.comparing(Child::getDate))
                      .ifPresent(d -> epp.add(d)));

Optional<Child> earliest = epp.stream()
                              .min(Comparator.comparing(Child::getDate));

Loop each parent, add the earliest per parent into the epp list, and then I loop the epp list to find the actual earliest.

Is this the most concise / best way to achieve with Java8?

Upvotes: 3

Views: 2410

Answers (1)

sprinter
sprinter

Reputation: 27976

Yes there is. You don't need to use the intermediate list if you flatten the map to children:

Optional<Child> earliest = parents.stream().
    .map(Parent::getChildren).flatMap(List::stream)
    .min(Comparator.comparing(Child::getDate));

If you are able to change the Parent class then you might want to add a streamChildren method in Parent:

class Parent {
    public Stream<Child> streamChildren() {
        return children.stream();
    }
}

This has the advantage of not giving the caller access to the underlying List.

As an aside, you didn't need to create your own ArrayList in the original solution. You could have used:

List<Child> earliest = parents.stream().map(Parent::getChildren)
    .map(children -> children.stream().min(Comparator(Child::getDate)))
    .filter(Optional::isPresent).map(Optional::get).distinct()
    .collect(Collectors.toList());

That avoids the side effect of the 'add' operation.

Upvotes: 3

Related Questions