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.