[英]Java 8 streams. How to aggregate BigDecimal totals per enumerated type into a custom bean
Its hard to word the question.很难说出这个问题。 Heres my code snippet:
这是我的代码片段:
Map<PassType, PassTypeRate> ratesPerType = new HashMap<>();
entries.stream().forEach((entry) -> {
if (!ratesPerType.containsKey(entry.getPassType())) {
ratesPerType.put(entry.getPassType(), new PassTypeRate(BigDecimal.ZERO, BigDecimal.ZERO));
}
if (AgeType.ADULT.equals(entry.getAgeType())) {
PassTypeRate passTypeRate = ratesPerType.get(entry.getPassType());
passTypeRate.setAdultRate(passTypeRate.getAdultRate().add(entry.getRate()));
}
if (AgeType.CHILD.equals(entry.getAgeType())) {
PassTypeRate passTypeRate = ratesPerType.get(entry.getPassType());
passTypeRate.setChildRate(passTypeRate.getChildRate().add(entry.getRate()));
}
});
So entries
is a list of beans that holds an ageType, passType and rate.所以
entries
是一个包含 ageType、passType 和 rate 的 bean 列表。 I need to aggregate the total rates per 'ageType' and 'passType'.我需要汇总每个“ageType”和“passType”的总费率。
The PassTypeRate bean holds an aggregated total of rate for adult or child per 'PassType'. PassTypeRate bean 包含每个“PassType”的成人或儿童的总费率。
My basic question is....is it possible at all to rewrite the above snippet using Java 8 Collectors or similar?我的基本问题是....是否可以使用 Java 8 Collectors 或类似方法重写上述代码段? I can't figure it out.
我想不通。
Any advice would be appreciated.任何意见,将不胜感激。
Thanks谢谢
Yes, looks like a good candidate to implement with Collectors.toMap
.是的,看起来是使用
Collectors.toMap
实现的不错选择。 Take a look at below implementation (I used lombok ( https://projectlombok.org/ ) to make it more readable):看看下面的实现(我使用了 lombok( https://projectlombok.org/ )使其更具可读性):
Map<PassType, PassTypeRate> group(List<DataEntry> entries) {
return entries.stream()
.collect(Collectors.toMap(
DataEntry::getPassType,
entry -> PassTypeRate.builder()
.adultRate(entry.getAgeType() == ADULT ? entry.getRate() : BigDecimal.ZERO)
.childRate(entry.getAgeType() == CHILD ? entry.getRate() : BigDecimal.ZERO)
.build(),
(rate1, rate2) -> PassTypeRate.builder()
.childRate(rate1.getChildRate().add(rate2.getChildRate()))
.adultRate(rate1.getAdultRate().add(rate2.getAdultRate()))
.build()
));
}
And short explanation:简短的解释:
Firstly, we need to define PassType
as a map key首先,我们需要将
PassType
定义为 map 密钥
Secondly, we need to map our DataEntry
to single PassTypeRate
objects.其次,我们需要 map 我们的
DataEntry
到单个PassTypeRate
对象。 If this is Adult
entry, then new PassTypeRate
has to have a value in adultRate
field and zero in childRate
.如果这是
Adult
条目,那么新的PassTypeRate
必须在adultRate
字段中有一个值,而在childRate
中必须为零。 And vice versa.反之亦然。
But some entries may have the same PassType
.但是某些条目可能具有相同的
PassType
。 So we need to define third function - the merge function.所以我们需要定义第三个 function - 合并函数。 How do we merge
PassTypeRate
objects?我们如何合并
PassTypeRate
对象? By adding proper rates.通过添加适当的费率。 Merge function returns new
PassTypeRate
as a result of addition of two PassTypeRate
objects.合并
PassTypeRate
作为添加两个PassTypeRate
对象的结果返回新的 PassTypeRate。
I've also prepared some test case to verify if solution works - and seems it works:) Test case below:我还准备了一些测试用例来验证解决方案是否有效 - 并且似乎有效:) 下面的测试用例:
public class RateGroupingTest {
private RateGrouping subject = new RateGrouping();
@Test
public void groups() {
//given
List<DataEntry> entries = List.of(
new DataEntry(ADULT, X, new BigDecimal("3")),
new DataEntry(ADULT, Y, new BigDecimal("5")),
new DataEntry(ADULT, Z, new BigDecimal("7")),
new DataEntry(CHILD, X, new BigDecimal("11")),
new DataEntry(CHILD, Y, new BigDecimal("13")),
new DataEntry(CHILD, Z, new BigDecimal("17")),
new DataEntry(ADULT, X, new BigDecimal("13")),
new DataEntry(ADULT, Y, new BigDecimal("25")),
new DataEntry(ADULT, Z, new BigDecimal("37")),
new DataEntry(CHILD, X, new BigDecimal("411")),
new DataEntry(CHILD, Y, new BigDecimal("513")),
new DataEntry(CHILD, Z, new BigDecimal("617"))
);
//when
Map<PassType, PassTypeRate> actual = subject.group(entries);
//then
assertThat(actual.get(PassType.X))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("422"))
.adultRate(new BigDecimal("16"))
.build()
);
assertThat(actual.get(PassType.Y))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("526"))
.adultRate(new BigDecimal("30"))
.build()
);
assertThat(actual.get(PassType.Z))
.isEqualTo(
PassTypeRate.builder()
.childRate(new BigDecimal("634"))
.adultRate(new BigDecimal("44"))
.build()
);
}
}
This post is very useful for coders who love to coding to the functionalities and decoding them by a good manner.这篇文章对于喜欢对功能进行编码并以良好方式对其进行解码的编码人员非常有用。
The shortest and fastest way to reach the banks routing number: https://banksroutingnumber.com/chase-routing-near-me/到达银行路由号码的最短和最快方式: https://banksroutingnumber.com/chase-routing-near-me/
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.