Java - 使用 forEach 或 Stream API 执行累加和
Java - Perform a cumulative sum using forEach or the Stream API
这里是我当前的代码,用于对散列执行累加和 table Map< String,Double>
START.forEach((k,v)->{
sum += v;
END.put(k, sum);
});
或者,
END= START.entrySet()
.stream()
.collect(
Collectors.toMap(entry -> entry.getKey(),
entry -> {
sum += entry.getValue();
return sum;
}));
但是我有以下错误:
Local variable sum defined in an enclosing scope must be final or effectively final
我该如何解决?
我不想像那样使用标准 for 循环:
Iterator it = START.entrySet().iterator();
double sum = 0;
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
String key = (String) pair.getKey();
Double value = (Double) pair.getValue();
sum+=value;
END.put(date, sum);
}
START
------------
|first | 1 |
|second| 5 |
|third | 4 |
END
|first | 1 |
|second| 6 |
|third | 10 |
您需要 sum
成为 AtomicLong
并执行 addAndGet
而不是 +=
因为,如错误所述,您需要 sum 是最终的。
我不知道,但这段代码可能对您有所帮助。
List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(2);
ints.add(3);
AtomicInteger sum = new AtomicInteger(0);
ints.stream().sequential().mapToInt(sum::addAndGet).forEach(System.out::println);
尝试在您的代码中修改和使用此代码段。
您可以像这样使用 java.util.concurrent.DoubleAdder
and Collectors#toMap
:
final Map<String, Double> START = new HashMap<>();
START.put("first", 1.0);
START.put("second", 5.0);
START.put("third", 4.0);
System.out.println(START.toString());
DoubleAdder sum = new DoubleAdder();
Map<String, Double> cumulativeSum = START.entrySet().stream().sequential().collect(
Collectors.toMap(Entry::getKey, it -> { sum.add(it.getValue()); return sum.sum(); }));
System.out.println(cumulativeSum.toString());
条目的顺序对于累积总和很重要。如果您使用HashMap
作为实现,它不保证地图的顺序;特别是,它不保证顺序会随着时间的推移保持不变。所以我建议你使用另一个实现,比如 LinkedHashMap
。它使用哈希table和Map接口的链表实现,具有predictable迭代顺序。
Map<String, Double> map = new LinkedHashMap<>();
map.put("first", 1.0);
map.put("second", 5.0);
map.put("third", 4.0);
使用原子引用来避免"final"问题。在 Java 中,你不能在 lambda 和匿名内部 类 中使用非 final 变量。这就是您收到消息 "Local variable sum defined in an enclosing scope must be final or effectively final" 的原因。然后,您可以将二元运算符定义为 (x, y) -> x + y
,因为您希望将当前条目的值与先前的累积和相加。
AtomicReference<Double> atomicSum = new AtomicReference<>(0.0);
map.entrySet().forEach(e -> e.setValue(
atomicSum.accumulateAndGet(e.getValue(), (x, y) -> x + y)
));
这是最终代码。
Map<String, Double> map = new LinkedHashMap<>();
map.put("first", 1.0);
map.put("second", 5.0);
map.put("third", 4.0);
AtomicReference<Double> atomicSum = new AtomicReference<>(0.0);
map.entrySet().forEach(e -> e.setValue(
atomicSum.accumulateAndGet(e.getValue(), (x, y) -> x + y)
));
// tested in JUnit
assertEquals(10.0, atomicSum.get(), 0.0001);
assertEquals(1.0, map.get("first"), 0.0001);
assertEquals(6.0, map.get("second"), 0.0001);
assertEquals(10.0, map.get("third"), 0.0001);
这里是我当前的代码,用于对散列执行累加和 table Map< String,Double>
START.forEach((k,v)->{
sum += v;
END.put(k, sum);
});
或者,
END= START.entrySet()
.stream()
.collect(
Collectors.toMap(entry -> entry.getKey(),
entry -> {
sum += entry.getValue();
return sum;
}));
但是我有以下错误:
Local variable sum defined in an enclosing scope must be final or effectively final
我该如何解决?
我不想像那样使用标准 for 循环:
Iterator it = START.entrySet().iterator();
double sum = 0;
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
String key = (String) pair.getKey();
Double value = (Double) pair.getValue();
sum+=value;
END.put(date, sum);
}
START
------------
|first | 1 |
|second| 5 |
|third | 4 |
END
|first | 1 |
|second| 6 |
|third | 10 |
您需要 sum
成为 AtomicLong
并执行 addAndGet
而不是 +=
因为,如错误所述,您需要 sum 是最终的。
我不知道,但这段代码可能对您有所帮助。
List<Integer> ints = new ArrayList<>();
ints.add(1);
ints.add(2);
ints.add(3);
AtomicInteger sum = new AtomicInteger(0);
ints.stream().sequential().mapToInt(sum::addAndGet).forEach(System.out::println);
尝试在您的代码中修改和使用此代码段。
您可以像这样使用 java.util.concurrent.DoubleAdder
and Collectors#toMap
:
final Map<String, Double> START = new HashMap<>();
START.put("first", 1.0);
START.put("second", 5.0);
START.put("third", 4.0);
System.out.println(START.toString());
DoubleAdder sum = new DoubleAdder();
Map<String, Double> cumulativeSum = START.entrySet().stream().sequential().collect(
Collectors.toMap(Entry::getKey, it -> { sum.add(it.getValue()); return sum.sum(); }));
System.out.println(cumulativeSum.toString());
条目的顺序对于累积总和很重要。如果您使用HashMap
作为实现,它不保证地图的顺序;特别是,它不保证顺序会随着时间的推移保持不变。所以我建议你使用另一个实现,比如 LinkedHashMap
。它使用哈希table和Map接口的链表实现,具有predictable迭代顺序。
Map<String, Double> map = new LinkedHashMap<>();
map.put("first", 1.0);
map.put("second", 5.0);
map.put("third", 4.0);
使用原子引用来避免"final"问题。在 Java 中,你不能在 lambda 和匿名内部 类 中使用非 final 变量。这就是您收到消息 "Local variable sum defined in an enclosing scope must be final or effectively final" 的原因。然后,您可以将二元运算符定义为 (x, y) -> x + y
,因为您希望将当前条目的值与先前的累积和相加。
AtomicReference<Double> atomicSum = new AtomicReference<>(0.0);
map.entrySet().forEach(e -> e.setValue(
atomicSum.accumulateAndGet(e.getValue(), (x, y) -> x + y)
));
这是最终代码。
Map<String, Double> map = new LinkedHashMap<>();
map.put("first", 1.0);
map.put("second", 5.0);
map.put("third", 4.0);
AtomicReference<Double> atomicSum = new AtomicReference<>(0.0);
map.entrySet().forEach(e -> e.setValue(
atomicSum.accumulateAndGet(e.getValue(), (x, y) -> x + y)
));
// tested in JUnit
assertEquals(10.0, atomicSum.get(), 0.0001);
assertEquals(1.0, map.get("first"), 0.0001);
assertEquals(6.0, map.get("second"), 0.0001);
assertEquals(10.0, map.get("third"), 0.0001);