I am looking at a code that has deeply nested for loop that I wanted to rewrite in a pure functional form using java-8 streams but what I see is that there are multiple values that are needed at each level and I am not sure how to approach to solve this in a clean way.

List<Report> reports = new ArrayList();
for (DigitalLogic dl : digitalLogics){
    for (Wizard wiz : dl.getWizards){
        for(Vice vice : wiz.getVices()){
           reports.add(createReport(dl, wiz, vice));
         }
    }
}

//
Report createReport(DigitalLogic dl, Wizard wiz, Vice vice){
  //Gets certain elements from all parameters and creates a report object
}

My real case scenario is much more complicated than this but I am wondering if there is a cleaner pure functional way of writing this using streams. Below is my initial attempt

List<Report> reports = new ArrayList();
digitalLogics.stream()
.map(dl -> dl.getWizards())
.flatMap(List::stream())
.map(wiz -> wiz.getVices())
.flatMap(List::stream())
.forEach(vice -> reports.add(createReport(?, ?, vice));

Obviously, I have lost the DigitalLogic and Wizard references.

2 Answers

1
Deadpool On

I will go with forEach method because stream solution makes this complicated

List<Report> reports = new ArrayList<>();
   digitalLogics.forEach(dl->dl.getWizards()
                .forEach(wiz->wiz.getVices()
                .forEach(v->reports.add(createReport(dl, wiz, v)))));
0
nullpointer On

Though currently what you have(for loops) is much cleaner than what it would be with streams, yet if you were to try it out :

public void createReports(List<DigitalLogic> digitalLogics) {
    List<Report> reports = digitalLogics.stream()
            .flatMap(dl -> dl.getWizards().stream()
                    .map(wizard -> new AbstractMap.SimpleEntry<>(dl, wizard)))
            .flatMap(entry -> entry.getValue().getVices().stream()
                    .map(vice -> createReport(entry.getKey(), entry.getValue(), vice)))
            .collect(Collectors.toList());
}