Reputation: 57
I try to use reduce to sum the HashMap value.
public class Link
{
private double[] flows;
public Link(double[] f) {
setFlows(f);
}
public double[] getFlows() {
return flows;
}
public void setFlows(double[] flows) {
this.flows = flows;
}
public static void main(String argv[])
{
// TEST for reduce on HashMap
HashMap<Integer, Link> id1 = new HashMap<Integer, Link>();
id1.put(1, new Link(new double[]{10,1,30}));
id1.put(2, new Link(new double[]{20,2,3}));
id1.put(3, new Link(new double[]{30,2,3}));
id1.put(4, new Link(new double[]{40,2,30}));
double[] my_sum = new double[3];
for (int i=0; i < 3; ++i)
{
my_sum[i] = id1.entrySet().stream().mapToDouble(e->e.getValue().getFlows()[i]).sum();
}
assert(my_sum[0] == 100);
assert(my_sum[1] == 7);
assert(my_sum[2] == 66);
}
}
In the for loop, I want to sum the value of each array item in the Link class. However, I have the problem with:
local variable defined in enclosing scope must be final or effectively final
Basically I don't want to define a final variable as class member, How to solve it?
Or is there a better to sum the value? (without the for loop?)
Upvotes: 1
Views: 1453
Reputation: 100279
An alternative which looks better to me is to use Arrays.setAll
:
double[] my_sum = new double[3];
Arrays.setAll(my_sum,
i -> id1.entrySet().stream().mapToDouble(e->e.getValue().getFlows()[i]).sum());
Here i
is effectively final.
Upvotes: 2
Reputation: 65859
If you add an add
method (making a Link
mutable unfortunately) you can use a Link
for the sum too.
// Makes it mutable - will try immutable later
public void add(Link other) {
for (int i = 0; i < flows.length; i++) {
flows[i] += other.flows[i];
}
}
public static void main(String argv[]) {
// TEST for reduce on HashMap
HashMap<Integer, Link> id1 = new HashMap<>();
id1.put(1, new Link(new double[]{10, 1, 30}));
id1.put(2, new Link(new double[]{20, 2, 3}));
id1.put(3, new Link(new double[]{30, 2, 3}));
id1.put(4, new Link(new double[]{40, 2, 30}));
Link sum = new Link(new double[3]);
id1.entrySet().stream().forEach(l -> sum.add(l.getValue()));
}
Upvotes: 0
Reputation: 137209
You're going at it the wrong way: you shouldn't have an external for
loop but handle everything inside a Stream pipeline.
You could make it work by storing the variable i
into a final local variable.
In the following code, only the values of the map are kept (since we're not interested in the keys). Then each value is mapped to their flows. Finally, the resulting Stream<double[]>
is reduced by first creating an array of 3 elements (initialized to 0) and then combining two double arrays into a resulting one by summing the value at the same index.
We have to rely on using a Stream over the indexes for that because there is no built-in facility for zipping two Streams together.
double[] my_sum =
id1.values().stream()
.map(Link::getFlows)
.reduce(
new double[3],
(v1, v2) -> IntStream.range(0, v2.length).mapToDouble(i -> v1[i] + v2[i]).toArray()
);
System.out.println(Arrays.toString(my_sum)); // prints [100.0, 7.0, 66.0]
Upvotes: 3