Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Iterating over two lists using Java 8 streams

How can I write the following in Java 8 streams?

int total = 0;
  for (ObjectA obja : rootObj.getListA()) {
    for (ObjectB objb : obja.getListB()) {
        total += objb.getCount() * obja.getCount();
    }
   }

return total;
like image 441
jliakos Avatar asked Dec 15 '22 14:12

jliakos


2 Answers

The canonical solution for converting nested for loops to Stream API usage is via flatMap:

return rootObj.getListA().stream()
.flatMapToInt(objA->objA.getListB().stream()
                                   .mapToInt(objB->objB.getCount() * objA.getCount()))
.sum();

This allows you to perform an operation for each inner iteration. However, in the special case of summing you may simplify the operation as it doesn’t matter whether you compute (a+b+c+d) or (a+b)+(c+d):

return rootObj.getListA().stream()
.mapToInt(objA->objA.getListB().stream()
                               .mapToInt(objB->objB.getCount() * objA.getCount()).sum())
.sum();

And when we are at remembering elementary arithmetics we should also recall that (a*x)+(b*x) is equal to (a+b)*x, in other words, there is no need to multiply every item of ListB with the count of objA as we can also just multiple the resulting sum with that count:

return rootObj.getListA().stream()
.mapToInt(objA->objA.getListB().stream().mapToInt(ObjectB::getCount).sum()*objA.getCount())
.sum();
like image 154
Holger Avatar answered Apr 24 '23 03:04

Holger


Here's an alternative solution which might be preferable in a number of cases:

int total = rootObj.getListA().stream()
    .flatMapToInt(objA -> objA.getListB()
         .stream().mapToInt(objB -> objB.getCount() * objA.getCount()))
    .sum();
like image 45
Tagir Valeev Avatar answered Apr 24 '23 03:04

Tagir Valeev