Home > Software engineering >  Use Java Streams to get max value for combination of parameters
Use Java Streams to get max value for combination of parameters

Time:11-23

I'm looking to transition this code to use Streams.

public ResultObject getBestObjectWithParameters() {
    int maxParameterValue = 10;
    double bestValue = 0.0;
    ResultObject bestObject = null;
    for (int a = 0; a < maxParameterValue; a  ) {
      for (int b = 0; b < maxParameterValue; b  ) {
        for (int c = 0; c < maxParameterValue; c  ) {
          ResultObject o = runCalculation(a, b, c);
          if (o.getValue() > bestValue) {
            bestValue = getValue;
            bestObject = o;
          }
        }
      }
    }
    return bestObject;
  }

In short, I'd like to runCalculation on every combination of parameters. runCalculation returns a ResultObject. I'd like to return the ResultObject that returns the maximum ResultObject.getValue().

Ideally, I would like to use parallel() to run this as quickly as possible.

What is the best way to do this?

CodePudding user response:

Here is a solution using a little class to wrap each calculation

import com.google.common.collect.Sets;

import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

class Scratch {
    public static void main(String[] args) {
        int maxParameterValue = 10;

        Set<Integer> params = IntStream.range(0, maxParameterValue).boxed().collect(Collectors.toSet());
        Result bestResult = Sets.cartesianProduct(params, params, params).stream()
                .parallel()
                .map(Result::new)
                .max(Comparator.comparingDouble(Result::getResult)).get();

        System.out.println(bestResult);
    }

    private static double runCalculation(int a, int b, int c) {
        // This just sums the 3 inputs replace with your function
        return a   b   c;
    }

    private static class Result {
        int a,b, c;
        double result;

        public Result(List<Integer> params) {
            this.a = params.get(0);
            this.b = params.get(1);
            this.c = params.get(2);
            this.result = runCalculation(a, b, c);
        }

        public double getResult() {
            return result;
        }

        @Override
        public String toString() {
            return String.format("Result{a=%d, b=%d, c=%d, result=%s}", a, b, c, result);
        }
    }
}

it uses Guava to generate the parameters

CodePudding user response:

It takes a few flatMap operations, but the following is the result:

public ResultObject getBestObjectWithParameters() {
    int maxParameterValue = 10;
    return IntStream.range(0, maxParameterValue)
            .mapToObj(a -> a) // Stream<Integer>
            .flatMap(a -> IntStream.range(0, maxParameterValue)
                    .mapToObj(b -> b) // Stream<Integer>
                    .flatMap(b -> IntStream.range(0, maxParameterValue)
                            .mapToObj(c -> c) // Stream<Integer>
                            .map(c -> runCalculation(a, b, c)) // Stream<ResultObject>
                     ) // Stream<resultObject>
            ) // Stream<ResultObject>
            .max(Comparator.comparingDouble(ResultObject::getValue))
            .orElse(null);
}

Note that I have to use mapToObj, because IntStream can only flatMap to an IntStream, not to a Stream<ResultObject>.

CodePudding user response:

Use IntStream and flatMap, as in:

  int maxParameterValue = 10;
          IntStream.range(0, maxParameterValue).boxed()
            .flatMap(i -> IntStream.range(0, maxParameterValue).boxed()
                .flatMap(j -> IntStream.range(0, maxParameterValue).boxed()
                    .map(k -> i   "-"   j   "-"   k)))
            .forEach(s -> System.out.println(s));

BTW, this was much more painful to write than it needed to be. Streams are nice, but other languages would make this so much more concise and not require the annoying .boxed() stuff.

  • Related