简体   繁体   English

Java 8 个流。 如何将每个枚举类型的 BigDecimal 总计聚合到自定义 bean

[英]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.

相关问题 Java 8 流。 将两个参数传递给在 forEach 中调用的方法 - Java 8 Streams. Pass Two arguments to a method called in forEach 如何对枚举类型Java使用.values() - How to use .values() with enumerated type Java 转换 Map <string,list<person> &gt; 至 Map <string,list<employee> &gt;,使用 Java 8 个流。 我这样做了,但是没有 for 循环怎么做</string,list<employee></string,list<person> - Convert Map<String,List<Person>> to Map<String,List<Employee>>, using Java 8 streams. I did this but how do this without for loop Java中枚举类型的问题 - Problem with enumerated type in Java 与Java中枚举类型的关系 - Relationship with Enumerated Type in Java 如何使用java流找到集合中最小的BigDecimal字段? - How to find minimum of BigDecimal field in collection with java streams? 如何使用带有地图和列表的Java 8 Streams计算两个子组的总数 - How to calculate totals of two subgroups using Java 8 Streams with maps and lists 如何使用自定义对象处理和聚合Kafka流? - How to process and aggregate Kafka Streams with custom Objects? 如何使用Java流计算两个聚合函数? - How to compute two aggregate functions with Java streams? 创建自定义BigDecimal类型 - Creating a custom BigDecimal type
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM