我有一个java对象,比如映射
此对象包含以下格式的数据:
202103, 2
202104, 4
202105, 0
202106, 9
.
.
.
.
202202, 10
第一个值是月份键,第二个值是案例计数。
我需要每月创建一个翻转数据或逐月累积的案例计数。
结果应该是-
202103, 2
202104, 6
202105, 6
202106, 15
.
.
.
.
202202, 98
我们如何在使用Java流时做到这一点。
首先,您需要对TreeMap
中的条目进行排序。
然后想不惜一切代价用流来解决这个问题,用iterate()
方法在for循环的条目集上累积你可能模拟的迭代值。
已排序映射的第一个条目用作种子。然后,对于流中创建的每个连续条目,较高条目的键将用作新条目的键,并用作较高条目的值与流中以前条目的值之和的值。该过程将继续,直到存在更高的条目,即getAccumeratedEntry()
返回的结果不是null
。此条件由谓词Objects::nonNull
表示。
public static void main(String[] args) {
Map<Integer, Long> monthCaseCount =
Map.of(202103, 2L,
202104, 4L,
202105, 0L,
202106, 9L);
NavigableMap<Integer, Long> monthCaseCountSorted = new TreeMap<>(monthCaseCount);
Map<Integer, Long> monthCaseCountAccumulated =
Stream.iterate(monthCaseCountSorted.firstEntry(),
Objects::nonNull,
entry -> getAccumulatedEntry(monthCaseCountSorted, entry))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
monthCaseCountAccumulated.entrySet().stream() // this part was added only for demonstration purpose
.sorted(Map.Entry.comparingByKey())
.forEach(entry -> System.out.printf("%d : %d%n", entry.getKey(), entry.getValue()));
}
private static Map.Entry<Integer, Long> getAccumulatedEntry(NavigableMap<Integer, Long> monthCaseCountSorted,
Map.Entry<Integer, Long> entry) {
Integer higher = monthCaseCountSorted.higherKey(entry.getKey());
return higher == null ?
null : Map.entry(higher, entry.getValue() + monthCaseCountSorted.get(higher));
}
输出
202103 : 2
202104 : 6
202105 : 6
202106 : 15
注意:更有效的方法是调整monthcasecontsorted
映射中的值。而流不适合这样的任务。函数不得产生副作用,且函数的每次执行都必须具有相同的结果(如果您试图通过直接更改monthCaseCountSorted
中的值来实现基于流的解决方案,则这两个条件都将被违反)
另一种选择是使用AtomicLong存储总和,并将累积值收集到新映射中:
Map<Integer, Long> monthCaseCountMap = Map.of( 202103, 2L,
202104, 4L,
202105, 0L,
202106, 9L);
AtomicLong sum = new AtomicLong(0L);
Map<Integer, Long> accumulated =
monthCaseCountMap.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(Map.Entry::getKey, e -> sum.addAndGet(e.getValue())));
你用错工具了。当您需要执行的操作是[A]仅对流中的单个元素执行的操作,或者[B]对所有元素执行的操作时,Java streams是合适的工具。
您需要对其中一些(特别是“前辈”)进行操作。从根本上说,Stream并不是为此而设计的。你用错工具了。流具有。parallel()
例如,从这个角度来看,“我面前所有东西的总和”的概念已经没有意义了。
你可以通过涉及排序的概念来重新定义这个问题(“我想要这个键的所有值和在这个键之前排序的所有值的总和”),但这将是非常低效的。
当你试图将一个工具用于它不是为之设计的东西时,这是可以预料的,流版本要么要慢得多,要么令人讨厌(混合流和非流概念,因此两者都有缺点,也都没有优点),而且很可能会有更多的代码和更复杂的代码。
只需使用迭代过程——您定义的操作在迭代思维下要简单得多。如果你想改进你的代码,请记住:你应该使用最具体的类型来准确描述你所拥有的Integer
没有太多说明,LocalDate
更准确,因为地图中的键显然是日期,或者至少是月-年。
public class Hospital {
SortedMap<LocalDate, Long> caseCounts = createCaseCountMap();
// createCaseCountMap ends up doing something like:
// caseCounts.put(LocalDate.of(2021, 03, 1), 2);
// caseCounts.put(LocalDate.of(2021, 04, 1), 4);
// .... etc
// option 1:
public long getSumUntil(LocalDate mark) {
return caseCounts.headMap(mark, true).values().stream()
.mapToLong(Long::longValue).sum();
}
// option 2:
public SortedMap<LocalDate, Long> makeIncrementalMap() {
var out = new TreeMap<LocalDate, Long>();
long sum = 0L;
for (var entry : caseCounts.entrySet()) {
sum += entry.getValue();
out.put(entry.getKey(), sum);
}
return out;
}
}
在这里,对于选项2,使用流是一个非常愚蠢的想法,因为操作基本上依赖于它的一些但不是所有的邻居,而流不是为这些邻居准备的。
这个问题似乎与帮助中心定义的范围内的编程无关。 我只是想使它的对象,并在控制台屏幕调用方法,但它是显示静态引用的错误。 请帮助我创建一个没有此静态引用错误的对象。
我正在努力实现以下布局。如果我选择curdate(),它是六月,我应该得到之前的6个月。6个月也应该包括六月。如果curdate=2018年6月25日至2018年1月,我的外出时间应该是从2018年6月至2018年1月的几个月。有谁能帮我解释一下语法吗。我现在有的只是个别的查询,这将给我在MySQL之前的6个月。 月份前几个月6月5月4月3月2月5月4月3月2月
我需要创建一个对象(银行),其中包含一组客户端和bankID。我的问题是,我不知道如何在主函数中创建银行。 银行类别: 客户端类: 主要类别: 这些是问题所在: 你必须创建一个程序来模拟银行活动。该系统包括以下模块:银行—客户(客户数组)— idBank(字符串)5 BancAccount — accountNumber(字符串)—金额(浮点)客户—姓名(字符串)—地址(字符串)—账户(银行账户数
问题内容: 输出为: 1988年 1月25 日星期三00:00:08 IST 1989 我过去了,但我得到了。为什么? 问题答案: 日历中的月份从零开始。因此,将12解释为12月+ 1个月。用
输出为: 1988 1989年1月25 00:00:08日星期三 我通过了1988年12月25日的考试,但我得到了1989年1月25日的考试。为什么?
我试图创建一个由子类定义的对象数组(我认为这是正确的术语)。我可以看到这个问题反复出现,但实现仍然存在问题。 我的代码 给出错误 线程“main”java.lang.NullPointerException中出现异常。 为了使其合理化,我将其分解为最简单的术语: 这似乎奏效了。我只是看不出我的两个例子有什么不同。我知道我的第一个没有意义,但是MyClass最终会包含更多的数据。) 我很肯定这个问题